merge-requests/30/head
Bob Mottram 2023-01-08 23:40:41 +00:00
commit 57f9a61a78
13 changed files with 409 additions and 308 deletions

View File

@ -1381,15 +1381,15 @@ def add_cw_from_lists(post_json_object: {}, cw_lists: {}, translate: {},
""" """
if not lists_enabled: if not lists_enabled:
return return
if not post_json_object['object'].get('content'): if 'content' not in post_json_object['object']:
if not post_json_object['object'].get('contentMap'): if 'contentMap' not in post_json_object['object']:
return return
cw_text = '' cw_text = ''
if post_json_object['object'].get('summary'): if post_json_object['object'].get('summary'):
cw_text = post_json_object['object']['summary'] cw_text = post_json_object['object']['summary']
content = None content = None
if post_json_object['object'].get('contentMap'): if 'contentMap' in post_json_object['object']:
if post_json_object['object']['contentMap'].get(system_language): if post_json_object['object']['contentMap'].get(system_language):
content = \ content = \
post_json_object['object']['contentMap'][system_language] post_json_object['object']['contentMap'][system_language]

View File

@ -2006,8 +2006,8 @@ def create_edits_html(edits_json: {}, post_json_object: {},
return '' return ''
if not has_object_dict(post_json_object): if not has_object_dict(post_json_object):
return '' return ''
if not post_json_object['object'].get('content'): if 'content' not in post_json_object['object']:
if not post_json_object['object'].get('contentMap'): if 'contentMap' not in post_json_object['object']:
return '' return ''
edit_dates_list = [] edit_dates_list = []
for modified, _ in edits_json.items(): for modified, _ in edits_json.items():
@ -2015,14 +2015,14 @@ def create_edits_html(edits_json: {}, post_json_object: {},
edit_dates_list.sort(reverse=True) edit_dates_list.sort(reverse=True)
edits_str = '' edits_str = ''
content = None content = None
if post_json_object['object'].get('contentMap'): if 'contentMap' in post_json_object['object']:
if post_json_object['object']['contentMap'].get(system_language): if post_json_object['object']['contentMap'].get(system_language):
content = \ content = \
post_json_object['object']['contentMap'][system_language] post_json_object['object']['contentMap'][system_language]
if not content: if content is None:
if post_json_object['object'].get('content'): if 'content' in post_json_object['object']:
content = post_json_object['object']['content'] content = post_json_object['object']['content']
if not content: if content is None:
return '' return ''
content = remove_html(content) content = remove_html(content)
for modified in edit_dates_list: for modified in edit_dates_list:
@ -2030,17 +2030,17 @@ def create_edits_html(edits_json: {}, post_json_object: {},
if not has_object_dict(prev_json): if not has_object_dict(prev_json):
continue continue
prev_content = None prev_content = None
if not prev_json['object'].get('content'): if 'content' not in prev_json['object']:
if not prev_json['object'].get('contentMap'): if 'contentMap' not in prev_json['object']:
continue continue
if prev_json['object'].get('contentMap'): if 'contentMap' in prev_json['object']:
if prev_json['object']['contentMap'].get(system_language): if prev_json['object']['contentMap'].get(system_language):
prev_content = \ prev_content = \
prev_json['object']['contentMap'][system_language] prev_json['object']['contentMap'][system_language]
if not prev_content: if prev_content is None:
if prev_json['object'].get('content'): if 'content' in prev_json['object']:
prev_content = prev_json['object']['content'] prev_content = prev_json['object']['content']
if not prev_content: if prev_content is None:
continue continue
prev_content = remove_html(prev_content) prev_content = remove_html(prev_content)
if content == prev_content: if content == prev_content:

View File

@ -2034,6 +2034,37 @@ class PubServer(BaseHTTPRequestHandler):
self._400() self._400()
self.server.postreq_busy = False self.server.postreq_busy = False
return 3 return 3
# if this is a local only post, is it really local?
if 'localOnly' in message_json['object'] and \
message_json['object'].get('to') and \
message_json['object'].get('attributedTo'):
if message_json['object']['localOnly'] is True:
# check that the to addresses are local
if isinstance(message_json['object']['to'], list):
for to_actor in message_json['object']['to']:
to_domain, to_port = \
get_domain_from_actor(to_actor)
to_domain_full = \
get_full_domain(to_domain, to_port)
if self.server.domain_full != to_domain_full:
print("REJECT: inbox " +
"local only post isn't local " +
str(message_json))
self._400()
self.server.postreq_busy = False
return 3
# check that the sender is local
local_actor = message_json['object']['attributedTo']
local_domain, local_port = \
get_domain_from_actor(local_actor)
local_domain_full = \
get_full_domain(local_domain, local_port)
if self.server.domain_full != local_domain_full:
print("REJECT: inbox local only post isn't local " +
str(message_json))
self._400()
self.server.postreq_busy = False
return 3
# actor should look like a url # actor should look like a url
if debug: if debug:
@ -4851,6 +4882,36 @@ class PubServer(BaseHTTPRequestHandler):
curr_session, proxy_type: str) -> None: curr_session, proxy_type: str) -> None:
"""Receive a vote via POST """Receive a vote via POST
""" """
first_post_id = ''
if '?firstpost=' in path:
first_post_id = path.split('?firstpost=')[1]
path = path.split('?firstpost=')[0]
if ';firstpost=' in path:
first_post_id = path.split(';firstpost=')[1]
path = path.split(';firstpost=')[0]
if first_post_id:
if '?' in first_post_id:
first_post_id = first_post_id.split('?')[0]
if ';' in first_post_id:
first_post_id = first_post_id.split(';')[0]
first_post_id = first_post_id.replace('/', '--')
first_post_id = ';firstpost=' + first_post_id.replace('#', '--')
last_post_id = ''
if '?lastpost=' in path:
last_post_id = path.split('?lastpost=')[1]
path = path.split('?lastpost=')[0]
if ';lastpost=' in path:
last_post_id = path.split(';lastpost=')[1]
path = path.split(';lastpost=')[0]
if last_post_id:
if '?' in last_post_id:
last_post_id = last_post_id.split('?')[0]
if ';' in last_post_id:
last_post_id = last_post_id.split(';')[0]
last_post_id = last_post_id.replace('/', '--')
last_post_id = ';lastpost=' + last_post_id.replace('#', '--')
page_number = 1 page_number = 1
if '?page=' in path: if '?page=' in path:
page_number_str = path.split('?page=')[1] page_number_str = path.split('?page=')[1]
@ -4860,7 +4921,6 @@ class PubServer(BaseHTTPRequestHandler):
page_number_str = "1" page_number_str = "1"
if page_number_str.isdigit(): if page_number_str.isdigit():
page_number = int(page_number_str) page_number = int(page_number_str)
path = path.split('?page=')[0]
# the actor who votes # the actor who votes
users_path = path.replace('/question', '') users_path = path.replace('/question', '')
@ -4926,7 +4986,7 @@ class PubServer(BaseHTTPRequestHandler):
actor = 'http://' + i2p_domain + users_path actor = 'http://' + i2p_domain + users_path
actor_path_str = \ actor_path_str = \
actor + '/' + self.server.default_timeline + \ actor + '/' + self.server.default_timeline + \
'?page=' + str(page_number) '?page=' + str(page_number) + first_post_id + last_post_id
self._redirect_headers(actor_path_str, cookie, self._redirect_headers(actor_path_str, cookie,
calling_domain) calling_domain)
self.server.postreq_busy = False self.server.postreq_busy = False
@ -21998,7 +22058,9 @@ class PubServer(BaseHTTPRequestHandler):
else: else:
# a vote/question/poll is posted # a vote/question/poll is posted
if self.path.endswith('/question') or \ if self.path.endswith('/question') or \
'/question?page=' in self.path: '/question?page=' in self.path or \
'/question?firstpost=' in self.path or \
'/question?lastpost=' in self.path:
self._receive_vote(calling_domain, cookie, self._receive_vote(calling_domain, cookie,
self.path, self.path,
self.server.http_prefix, self.server.http_prefix,

File diff suppressed because one or more lines are too long

View File

@ -772,10 +772,10 @@ a:focus {
} }
.container img.attachment { .container img.attachment {
max-width: 140%; width: 125%;
max-width: 145%;
margin-left: -2%; margin-left: -2%;
margin-right: 2%; margin-right: 2%;
width: 125%;
padding-bottom: 3%; padding-bottom: 3%;
} }

View File

@ -341,7 +341,7 @@ def store_hash_tags(base_dir: str, nickname: str, domain: str,
# get geolocations from content # get geolocations from content
map_links = [] map_links = []
published = None published = None
if post_json_object['object'].get('content'): if 'content' in post_json_object['object']:
published = post_json_object['object']['published'] published = post_json_object['object']['published']
post_content = post_json_object['object']['content'] post_content = post_json_object['object']['content']
map_links += get_map_links_from_post_content(post_content) map_links += get_map_links_from_post_content(post_content)
@ -898,7 +898,8 @@ def _inbox_post_recipients(base_dir: str, post_json_object: {},
else: else:
if debug and post_json_object.get('object'): if debug and post_json_object.get('object'):
if isinstance(post_json_object['object'], str): if isinstance(post_json_object['object'], str):
if '/statuses/' in post_json_object['object']: if '/statuses/' in post_json_object['object'] or \
'/objects/' in post_json_object['object']:
print('DEBUG: inbox item is a link to a post') print('DEBUG: inbox item is a link to a post')
else: else:
if '/users/' in post_json_object['object']: if '/users/' in post_json_object['object']:
@ -1294,9 +1295,9 @@ def receive_edit_to_post(recent_posts_cache: {}, message_json: {},
return False return False
if not has_object_dict(post_json_object): if not has_object_dict(post_json_object):
return False return False
if not post_json_object['object'].get('content'): if 'content' not in post_json_object['object']:
return False return False
if not message_json['object'].get('content'): if 'content' not in message_json['object']:
return False return False
# does the actor match? # does the actor match?
if post_json_object['actor'] != message_json['actor']: if post_json_object['actor'] != message_json['actor']:
@ -1775,7 +1776,7 @@ def _receive_reaction(recent_posts_cache: {},
return False return False
if not has_object_string(message_json, debug): if not has_object_string(message_json, debug):
return False return False
if not message_json.get('content'): if 'content' not in message_json:
if debug: if debug:
print('DEBUG: ' + message_json['type'] + ' has no "content"') print('DEBUG: ' + message_json['type'] + ' has no "content"')
return False return False
@ -1938,7 +1939,7 @@ def _receive_zot_reaction(recent_posts_cache: {},
return False return False
if message_json['object']['type'] != 'Note': if message_json['object']['type'] != 'Note':
return False return False
if not message_json['object'].get('content'): if 'content' not in message_json['object']:
if debug: if debug:
print('DEBUG: ' + message_json['object']['type'] + print('DEBUG: ' + message_json['object']['type'] +
' has no "content"') ' has no "content"')
@ -2118,7 +2119,7 @@ def _receive_undo_reaction(recent_posts_cache: {},
return False return False
if not has_object_string_object(message_json, debug): if not has_object_string_object(message_json, debug):
return False return False
if not message_json['object'].get('content'): if 'content' not in message_json['object']:
if debug: if debug:
print('DEBUG: ' + message_json['type'] + ' has no "content"') print('DEBUG: ' + message_json['type'] + ' has no "content"')
return False return False
@ -2774,6 +2775,8 @@ def _receive_announce(recent_posts_cache: {},
if has_users_path(lookup_actor): if has_users_path(lookup_actor):
if '/statuses/' in lookup_actor: if '/statuses/' in lookup_actor:
lookup_actor = lookup_actor.split('/statuses/')[0] lookup_actor = lookup_actor.split('/statuses/')[0]
elif '/objects/' in lookup_actor:
lookup_actor = lookup_actor.split('/objects/')[0]
if is_recent_post(post_json_object, 3): if is_recent_post(post_json_object, 3):
if not os.path.isfile(post_filename + '.tts'): if not os.path.isfile(post_filename + '.tts'):
@ -3009,7 +3012,7 @@ def _valid_post_content(base_dir: str, nickname: str, domain: str,
""" """
if not has_object_dict(message_json): if not has_object_dict(message_json):
return True return True
if not message_json['object'].get('content'): if 'content' not in message_json['object']:
return True return True
if not message_json['object'].get('published'): if not message_json['object'].get('published'):

View File

@ -207,7 +207,7 @@ def _capitalize_hashtag(content: str, message_json: {},
if '#' + original_tag not in content: if '#' + original_tag not in content:
return return
content = content.replace('#' + original_tag, '#' + capitalized_tag) content = content.replace('#' + original_tag, '#' + capitalized_tag)
if message_json['object'].get('contentMap'): if 'contentMap' in message_json['object']:
if message_json['object']['contentMap'].get(system_language): if message_json['object']['contentMap'].get(system_language):
message_json['object']['contentMap'][system_language] = content message_json['object']['contentMap'][system_language] = content
message_json['object']['contentMap'][system_language] = content message_json['object']['contentMap'][system_language] = content
@ -265,6 +265,29 @@ def post_message_to_outbox(session, translate: {},
# check that the outgoing post doesn't contain any markup # check that the outgoing post doesn't contain any markup
# which can be used to implement exploits # which can be used to implement exploits
if has_object_dict(message_json): if has_object_dict(message_json):
# if this is a local only post, is it really local?
if 'localOnly' in message_json['object'] and \
message_json['object'].get('to') and \
message_json['object'].get('attributedTo'):
if message_json['object']['localOnly'] is True:
# check that the to addresses are local
if isinstance(message_json['object']['to'], list):
for to_actor in message_json['object']['to']:
to_domain, to_port = get_domain_from_actor(to_actor)
to_domain_full = get_full_domain(to_domain, to_port)
if domain_full != to_domain_full:
print("REJECT: local only post isn't local " +
str(message_json))
return False
# check that the sender is local
local_actor = message_json['object']['attributedTo']
local_domain, local_port = get_domain_from_actor(local_actor)
local_domain_full = get_full_domain(local_domain, local_port)
if domain_full != local_domain_full:
print("REJECT: local only post isn't local " +
str(message_json))
return False
if is_quote_toot(message_json, ''): if is_quote_toot(message_json, ''):
print('REJECT: POST quote toot ' + str(message_json)) print('REJECT: POST quote toot ' + str(message_json))
return False return False

View File

@ -1199,7 +1199,8 @@ def can_remove_post(base_dir: str,
domain: str, port: int, post_id: str) -> bool: domain: str, port: int, post_id: str) -> bool:
"""Returns true if the given post can be removed """Returns true if the given post can be removed
""" """
if '/statuses/' not in post_id: if '/statuses/' not in post_id and \
'/objects/' not in post_id:
return False return False
domain_full = get_full_domain(domain, port) domain_full = get_full_domain(domain, port)

View File

@ -5240,6 +5240,9 @@ def download_announce(session, base_dir: str, http_prefix: str,
base_dir, nickname, domain, post_id, base_dir, nickname, domain, post_id,
recent_posts_cache) recent_posts_cache)
return None return None
announced_actor = announced_json['id']
if announced_json.get('attributedTo'):
announced_actor = announced_json['attributedTo']
if not announced_json.get('type'): if not announced_json.get('type'):
print('WARN: announced post does not have a type ' + print('WARN: announced post does not have a type ' +
str(announced_json)) str(announced_json))
@ -5254,14 +5257,15 @@ def download_announce(session, base_dir: str, http_prefix: str,
announced_json, blocked_cache) announced_json, blocked_cache)
if converted_json: if converted_json:
announced_json = converted_json announced_json = converted_json
if '/statuses/' not in announced_json['id']: if '/statuses/' not in announced_json['id'] and \
'/objects/' not in announced_json['id']:
print('WARN: announced post id does not contain /statuses/ ' + print('WARN: announced post id does not contain /statuses/ ' +
str(announced_json)) 'or /objects/' + str(announced_json))
_reject_announce(announce_filename, _reject_announce(announce_filename,
base_dir, nickname, domain, post_id, base_dir, nickname, domain, post_id,
recent_posts_cache) recent_posts_cache)
return None return None
if not has_users_path(announced_json['id']): if not has_users_path(announced_actor):
print('WARN: announced post id does not contain /users/ ' + print('WARN: announced post id does not contain /users/ ' +
str(announced_json)) str(announced_json))
_reject_announce(announce_filename, _reject_announce(announce_filename,
@ -5278,7 +5282,7 @@ def download_announce(session, base_dir: str, http_prefix: str,
base_dir, nickname, domain, post_id, base_dir, nickname, domain, post_id,
recent_posts_cache) recent_posts_cache)
return None return None
if not announced_json.get('content'): if 'content' not in announced_json:
print('WARN: announced post does not have content ' + print('WARN: announced post does not have content ' +
str(announced_json)) str(announced_json))
_reject_announce(announce_filename, _reject_announce(announce_filename,
@ -5311,7 +5315,7 @@ def download_announce(session, base_dir: str, http_prefix: str,
# Check the content of the announce # Check the content of the announce
content_str = announced_json['content'] content_str = announced_json['content']
using_content_map = False using_content_map = False
if announced_json.get('contentMap'): if 'contentMap' in announced_json:
if announced_json['contentMap'].get(system_language): if announced_json['contentMap'].get(system_language):
content_str = announced_json['contentMap'][system_language] content_str = announced_json['contentMap'][system_language]
using_content_map = True using_content_map = True
@ -5875,7 +5879,7 @@ def edited_post_filename(base_dir: str, nickname: str, domain: str,
return '', None return '', None
if not post_json_object['object'].get('id'): if not post_json_object['object'].get('id'):
return '', None return '', None
if not post_json_object['object'].get('content'): if 'content' not in post_json_object['object']:
return '', None return '', None
if not post_json_object['object'].get('attributedTo'): if not post_json_object['object'].get('attributedTo'):
return '', None return '', None
@ -5919,7 +5923,7 @@ def edited_post_filename(base_dir: str, nickname: str, domain: str,
return '', None return '', None
if not lastpost_json['object'].get('id'): if not lastpost_json['object'].get('id'):
return '', None return '', None
if not lastpost_json['object'].get('content'): if 'content' not in lastpost_json['object']:
return '', None return '', None
if not lastpost_json['object'].get('attributedTo'): if not lastpost_json['object'].get('attributedTo'):
return '', None return '', None
@ -5933,12 +5937,12 @@ def edited_post_filename(base_dir: str, nickname: str, domain: str,
if debug: if debug:
print(post_id + ' might be an edit of ' + lastpost_id) print(post_id + ' might be an edit of ' + lastpost_id)
lastpost_content = lastpost_json['object']['content'] lastpost_content = lastpost_json['object']['content']
if lastpost_json['object'].get('contentMap'): if 'contentMap' in lastpost_json['object']:
if lastpost_json['object']['contentMap'].get(system_language): if lastpost_json['object']['contentMap'].get(system_language):
lastpost_content = \ lastpost_content = \
lastpost_json['object']['contentMap'][system_language] lastpost_json['object']['contentMap'][system_language]
content = post_json_object['object']['content'] content = post_json_object['object']['content']
if post_json_object['object'].get('contentMap'): if 'contentMap' in post_json_object['object']:
if post_json_object['object']['contentMap'].get(system_language): if post_json_object['object']['contentMap'].get(system_language):
content = \ content = \
post_json_object['object']['contentMap'][system_language] post_json_object['object']['contentMap'][system_language]

View File

@ -287,7 +287,7 @@ def get_base_content_from_post(post_json_object: {},
this_post_json = post_json_object this_post_json = post_json_object
if has_object_dict(post_json_object): if has_object_dict(post_json_object):
this_post_json = post_json_object['object'] this_post_json = post_json_object['object']
if not this_post_json.get('content'): if 'content' not in this_post_json:
return '' return ''
return this_post_json['content'] return this_post_json['content']
@ -2571,7 +2571,7 @@ def is_blog_post(post_json_object: {}) -> bool:
return False return False
if not has_object_string_type(post_json_object, False): if not has_object_string_type(post_json_object, False):
return False return False
if not post_json_object['object'].get('content'): if 'content' not in post_json_object['object']:
return False return False
if post_json_object['object']['type'] != 'Article': if post_json_object['object']['type'] != 'Article':
return False return False
@ -4164,11 +4164,12 @@ def save_reverse_timeline(base_dir: str, reverse_sequence: []) -> []:
def is_quote_toot(post_json_object: str, content: str) -> bool: def is_quote_toot(post_json_object: str, content: str) -> bool:
"""Returns true if the given post is a quote toot """Returns true if the given post is a quote toot
""" """
# Pleroma implementation # Pleroma/Misskey implementations
if post_json_object['object'].get('quoteUri') or \ if post_json_object['object'].get('quoteUri') or \
post_json_object['object'].get('quoteUrl'): post_json_object['object'].get('quoteUrl') or \
post_json_object['object'].get('_misskey_quote'):
return True return True
# More correct ActivityPub implementation # More correct ActivityPub implementation - adding a Link tag
if post_json_object['object'].get('tag'): if post_json_object['object'].get('tag'):
if isinstance(post_json_object['object']['tag'], list): if isinstance(post_json_object['object']['tag'], list):
for item in post_json_object['object']['tag']: for item in post_json_object['object']['tag']:
@ -4187,6 +4188,7 @@ def is_quote_toot(post_json_object: str, content: str) -> bool:
if 'json' not in item['mediaType']: if 'json' not in item['mediaType']:
continue continue
return True return True
# Twitter-style indicator
if content: if content:
if 'QT: ' in content: if 'QT: ' in content:
return True return True

View File

@ -91,7 +91,7 @@ def convert_video_to_note(base_dir: str, nickname: str, domain: str,
return None return None
content += '<p>' + post_json_object['license']['name'] + '</p>' content += '<p>' + post_json_object['license']['name'] + '</p>'
post_content = post_json_object['content'] post_content = post_json_object['content']
if post_json_object.get('contentMap'): if 'contentMap' in post_json_object:
if post_json_object['contentMap'].get(system_language): if post_json_object['contentMap'].get(system_language):
post_content = post_json_object['contentMap'][system_language] post_content = post_json_object['contentMap'][system_language]
content += post_content content += post_content

View File

@ -158,9 +158,9 @@ def _html_post_metadata_open_graph(domain: str, post_json_object: {},
" <meta content=\"" + obj_json['published'] + \ " <meta content=\"" + obj_json['published'] + \
"\" property=\"og:published_time\" />\n" "\" property=\"og:published_time\" />\n"
if not obj_json.get('attachment') or obj_json.get('sensitive'): if not obj_json.get('attachment') or obj_json.get('sensitive'):
if obj_json.get('content') and not obj_json.get('sensitive'): if 'content' in obj_json and not obj_json.get('sensitive'):
obj_content = obj_json['content'] obj_content = obj_json['content']
if obj_json.get('contentMap'): if 'contentMap' in obj_json:
if obj_json['contentMap'].get(system_language): if obj_json['contentMap'].get(system_language):
obj_content = obj_json['contentMap'][system_language] obj_content = obj_json['contentMap'][system_language]
description = remove_html(obj_content) description = remove_html(obj_content)
@ -190,9 +190,9 @@ def _html_post_metadata_open_graph(domain: str, post_json_object: {},
elif attach_json['mediaType'].startswith('audio/'): elif attach_json['mediaType'].startswith('audio/'):
description = 'Attached: 1 audio' description = 'Attached: 1 audio'
if description: if description:
if obj_json.get('content') and not obj_json.get('sensitive'): if 'content' in obj_json and not obj_json.get('sensitive'):
obj_content = obj_json['content'] obj_content = obj_json['content']
if obj_json.get('contentMap'): if 'contentMap' in obj_json:
if obj_json['contentMap'].get(system_language): if obj_json['contentMap'].get(system_language):
obj_content = obj_json['contentMap'][system_language] obj_content = obj_json['contentMap'][system_language]
description += '\n\n' + remove_html(obj_content) description += '\n\n' + remove_html(obj_content)

View File

@ -1333,7 +1333,7 @@ def rss_hashtag_search(nickname: str, domain: str, port: int,
break break
continue continue
# add to feed # add to feed
if post_json_object['object'].get('content') and \ if 'content' in post_json_object['object'] and \
post_json_object['object'].get('attributedTo') and \ post_json_object['object'].get('attributedTo') and \
post_json_object['object'].get('published'): post_json_object['object'].get('published'):
published = post_json_object['object']['published'] published = post_json_object['object']['published']