Merge branch 'main' of gitlab.com:bashrc2/epicyon

merge-requests/30/head
Bob Mottram 2022-10-31 19:07:48 +00:00
commit 548437df96
11 changed files with 109 additions and 6 deletions

View File

@ -1437,6 +1437,7 @@ def save_media_in_form_post(media_bytes, debug: bool,
'svg': 'image/svg+xml', 'svg': 'image/svg+xml',
'webp': 'image/webp', 'webp': 'image/webp',
'avif': 'image/avif', 'avif': 'image/avif',
'heic': 'image/heic',
'mp4': 'video/mp4', 'mp4': 'video/mp4',
'ogv': 'video/ogv', 'ogv': 'video/ogv',
'mp3': 'audio/mpeg', 'mp3': 'audio/mpeg',

View File

@ -1499,6 +1499,76 @@ class PubServer(BaseHTTPRequestHandler):
self.server.nodeinfo_is_active = False self.server.nodeinfo_is_active = False
return True return True
def _security_txt(self, ua_str: str, calling_domain: str,
referer_domain: str,
http_prefix: str, calling_site_timeout: int,
debug: bool) -> bool:
"""See https://www.rfc-editor.org/rfc/rfc9116
"""
if not self.path.startswith('/security.txt'):
return False
if referer_domain == self.server.domain_full:
print('security.txt request from self')
self._400()
return True
if self.server.security_txt_is_active:
if not referer_domain:
print('security.txt is busy ' +
'during request without referer domain')
else:
print('security.txt is busy during request from ' +
referer_domain)
self._503()
return True
self.server.security_txt_is_active = True
# is this a real website making the call ?
if not debug and not self.server.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('security.txt ' +
'referer domain does not look like a domain ' +
referer_domain)
self._400()
self.server.security_txt_is_active = False
return True
if not self.server.allow_local_network_access:
if local_network_host(referer_domain):
print('security.txt referer domain is from the ' +
'local network ' + referer_domain)
self._400()
self.server.security_txt_is_active = False
return True
if not referer_is_active(http_prefix,
referer_domain, ua_str,
calling_site_timeout):
print('security.txt referer url is not active ' +
referer_domain)
self._400()
self.server.security_txt_is_active = False
return True
if self.server.debug:
print('DEBUG: security.txt ' + self.path)
# If we are in broch mode then don't reply
if not broch_mode_is_active(self.server.base_dir):
security_txt = \
'Contact: https://gitlab.com/bashrc2/epicyon/-/issues'
msg = security_txt.encode('utf-8')
msglen = len(msg)
self._set_headers('text/plain; charset=utf-8',
msglen, None, calling_domain, True)
self._write(msg)
if referer_domain:
print('security.txt sent to ' + referer_domain)
else:
print('security.txt sent to unknown referer')
self.server.security_txt_is_active = False
return True
def _webfinger(self, calling_domain: str, referer_domain: str) -> bool: def _webfinger(self, calling_domain: str, referer_domain: str) -> bool:
if not self.path.startswith('/.well-known'): if not self.path.startswith('/.well-known'):
return False return False
@ -7529,6 +7599,9 @@ class PubServer(BaseHTTPRequestHandler):
if 'image/avif' in self.headers['Accept']: if 'image/avif' in self.headers['Accept']:
fav_type = 'image/avif' fav_type = 'image/avif'
fav_filename = fav_filename.split('.')[0] + '.avif' fav_filename = fav_filename.split('.')[0] + '.avif'
if 'image/heic' in self.headers['Accept']:
fav_type = 'image/heic'
fav_filename = fav_filename.split('.')[0] + '.heic'
if 'image/jxl' in self.headers['Accept']: if 'image/jxl' in self.headers['Accept']:
fav_type = 'image/jxl' fav_type = 'image/jxl'
fav_filename = fav_filename.split('.')[0] + '.jxl' fav_filename = fav_filename.split('.')[0] + '.jxl'
@ -7546,6 +7619,8 @@ class PubServer(BaseHTTPRequestHandler):
fav_filename = fav_filename.replace('.webp', '.ico') fav_filename = fav_filename.replace('.webp', '.ico')
elif fav_filename.endswith('.avif'): elif fav_filename.endswith('.avif'):
fav_filename = fav_filename.replace('.avif', '.ico') fav_filename = fav_filename.replace('.avif', '.ico')
elif fav_filename.endswith('.heic'):
fav_filename = fav_filename.replace('.heic', '.ico')
elif fav_filename.endswith('.jxl'): elif fav_filename.endswith('.jxl'):
fav_filename = fav_filename.replace('.jxl', '.ico') fav_filename = fav_filename.replace('.jxl', '.ico')
if not os.path.isfile(favicon_filename): if not os.path.isfile(favicon_filename):
@ -15281,6 +15356,14 @@ class PubServer(BaseHTTPRequestHandler):
'_GET', '_nodeinfo[calling_domain]', '_GET', '_nodeinfo[calling_domain]',
self.server.debug) self.server.debug)
if self._security_txt(ua_str, calling_domain, referer_domain,
self.server.http_prefix, 5, self.server.debug):
return
fitness_performance(getreq_start_time, self.server.fitness,
'_GET', '_security_txt[calling_domain]',
self.server.debug)
if self.path == '/logout': if self.path == '/logout':
if not self.server.news_instance: if not self.server.news_instance:
msg = \ msg = \
@ -21115,6 +21198,7 @@ def run_daemon(map_format: str,
httpd.post_to_nickname = None httpd.post_to_nickname = None
httpd.nodeinfo_is_active = False httpd.nodeinfo_is_active = False
httpd.security_txt_is_active = False
httpd.vcard_is_active = False httpd.vcard_is_active = False
httpd.masto_api_is_active = False httpd.masto_api_is_active = False

View File

@ -188,6 +188,7 @@ def meta_data_instance(show_accounts: bool,
'image/gif', 'image/gif',
'image/webp', 'image/webp',
'image/avif', 'image/avif',
'image/heic',
'image/svg+xml', 'image/svg+xml',
'video/webm', 'video/webm',
'video/mp4', 'video/mp4',

View File

@ -170,6 +170,7 @@ def _download_newswire_feed_favicon(session, base_dir: str,
'jxl': 'jxl', 'jxl': 'jxl',
'gif': 'gif', 'gif': 'gif',
'avif': 'avif', 'avif': 'avif',
'heic': 'heic',
'svg': 'svg+xml', 'svg': 'svg+xml',
'webp': 'webp' 'webp': 'webp'
} }

View File

@ -351,6 +351,7 @@ def post_message_to_outbox(session, translate: {},
"svg": "svg", "svg": "svg",
"webp": "webp", "webp": "webp",
"avif": "avif", "avif": "avif",
"heic": "heic",
"audio/mpeg": "mp3", "audio/mpeg": "mp3",
"ogg": "ogg", "ogg": "ogg",
"audio/wav": "wav", "audio/wav": "wav",

View File

@ -146,6 +146,9 @@ def set_profile_image(base_dir: str, http_prefix: str,
elif image_filename.endswith('.avif'): elif image_filename.endswith('.avif'):
media_type = 'image/avif' media_type = 'image/avif'
icon_filename = icon_filename_base + '.avif' icon_filename = icon_filename_base + '.avif'
elif image_filename.endswith('.heic'):
media_type = 'image/heic'
icon_filename = icon_filename_base + '.heic'
elif image_filename.endswith('.jxl'): elif image_filename.endswith('.jxl'):
media_type = 'image/jxl' media_type = 'image/jxl'
icon_filename = icon_filename_base + '.jxl' icon_filename = icon_filename_base + '.jxl'

View File

@ -535,7 +535,7 @@ def post_image(session, attach_image_filename: str, federation_list: [],
return None return None
if not is_image_file(attach_image_filename): if not is_image_file(attach_image_filename):
print('Image must be png, jpg, jxl, webp, avif, gif or svg') print('Image must be png, jpg, jxl, webp, avif, heic, gif or svg')
return None return None
if not os.path.isfile(attach_image_filename): if not os.path.isfile(attach_image_filename):
print('Image not found: ' + attach_image_filename) print('Image not found: ' + attach_image_filename)
@ -549,6 +549,8 @@ def post_image(session, attach_image_filename: str, federation_list: [],
content_type = 'image/webp' content_type = 'image/webp'
elif attach_image_filename.endswith('.avif'): elif attach_image_filename.endswith('.avif'):
content_type = 'image/avif' content_type = 'image/avif'
elif attach_image_filename.endswith('.heic'):
content_type = 'image/heic'
elif attach_image_filename.endswith('.jxl'): elif attach_image_filename.endswith('.jxl'):
content_type = 'image/jxl' content_type = 'image/jxl'
elif attach_image_filename.endswith('.svg'): elif attach_image_filename.endswith('.svg'):
@ -612,6 +614,7 @@ def download_image(session, url: str, image_filename: str, debug: bool,
'svg': 'svg+xml', 'svg': 'svg+xml',
'webp': 'webp', 'webp': 'webp',
'avif': 'avif', 'avif': 'avif',
'heic': 'heic',
'ico': 'x-icon' 'ico': 'x-icon'
} }
session_headers = None session_headers = None
@ -722,7 +725,8 @@ def download_image_any_mime_type(session, url: str,
'gif': 'gif', 'gif': 'gif',
'svg': 'svg+xml', 'svg': 'svg+xml',
'webp': 'webp', 'webp': 'webp',
'avif': 'avif' 'avif': 'avif',
'heic': 'heic'
} }
for _, m_type in image_formats.items(): for _, m_type in image_formats.items():
if 'image/' + m_type in content_type: if 'image/' + m_type in content_type:

View File

@ -496,7 +496,8 @@ def get_audio_extensions() -> []:
def get_image_extensions() -> []: def get_image_extensions() -> []:
"""Returns a list of the possible image file extensions """Returns a list of the possible image file extensions
""" """
return ('jpg', 'jpeg', 'gif', 'webp', 'avif', 'svg', 'ico', 'jxl', 'png') return ('jpg', 'jpeg', 'gif', 'webp', 'avif', 'heic',
'svg', 'ico', 'jxl', 'png')
def get_image_mime_type(image_filename: str) -> str: def get_image_mime_type(image_filename: str) -> str:
@ -508,6 +509,7 @@ def get_image_mime_type(image_filename: str) -> str:
'jxl': 'jxl', 'jxl': 'jxl',
'gif': 'gif', 'gif': 'gif',
'avif': 'avif', 'avif': 'avif',
'heic': 'heic',
'svg': 'svg+xml', 'svg': 'svg+xml',
'webp': 'webp', 'webp': 'webp',
'ico': 'x-icon' 'ico': 'x-icon'
@ -529,6 +531,7 @@ def get_image_extension_from_mime_type(content_type: str) -> str:
'svg+xml': 'svg', 'svg+xml': 'svg',
'webp': 'webp', 'webp': 'webp',
'avif': 'avif', 'avif': 'avif',
'heic': 'heic',
'x-icon': 'ico' 'x-icon': 'ico'
} }
for mime_ext, ext in image_media.items(): for mime_ext, ext in image_media.items():
@ -2894,6 +2897,7 @@ def media_file_mime_type(filename: str) -> str:
'svg': 'image/svg+xml', 'svg': 'image/svg+xml',
'webp': 'image/webp', 'webp': 'image/webp',
'avif': 'image/avif', 'avif': 'image/avif',
'heic': 'image/heic',
'ico': 'image/x-icon', 'ico': 'image/x-icon',
'mp3': 'audio/mpeg', 'mp3': 'audio/mpeg',
'ogg': 'audio/ogg', 'ogg': 'audio/ogg',

View File

@ -255,7 +255,7 @@ def _html_newswire(base_dir: str, newswire: {}, nickname: str, moderator: bool,
cached_favicon_filename.replace(base_dir, '') cached_favicon_filename.replace(base_dir, '')
else: else:
extensions = \ extensions = \
('png', 'jpg', 'gif', 'avif', 'svg', 'webp', 'jxl') ('png', 'jpg', 'gif', 'avif', 'heic', 'svg', 'webp', 'jxl')
for ext in extensions: for ext in extensions:
cached_favicon_filename = \ cached_favicon_filename = \
get_fav_filename_from_url(base_dir, favicon_url) get_fav_filename_from_url(base_dir, favicon_url)

View File

@ -88,6 +88,9 @@ def html_login(translate: {},
elif os.path.isfile(base_dir + '/accounts/login.avif'): elif os.path.isfile(base_dir + '/accounts/login.avif'):
login_image = 'login.avif' login_image = 'login.avif'
login_image_filename = base_dir + '/accounts/' + login_image login_image_filename = base_dir + '/accounts/' + login_image
elif os.path.isfile(base_dir + '/accounts/login.heic'):
login_image = 'login.heic'
login_image_filename = base_dir + '/accounts/' + login_image
elif os.path.isfile(base_dir + '/accounts/login.jxl'): elif os.path.isfile(base_dir + '/accounts/login.jxl'):
login_image = 'login.jxl' login_image = 'login.jxl'
login_image_filename = base_dir + '/accounts/' + login_image login_image_filename = base_dir + '/accounts/' + login_image

View File

@ -321,7 +321,8 @@ def update_avatar_image_cache(signing_priv_key_pem: str,
'gif': 'gif', 'gif': 'gif',
'svg': 'svg+xml', 'svg': 'svg+xml',
'webp': 'webp', 'webp': 'webp',
'avif': 'avif' 'avif': 'avif',
'heic': 'heic'
} }
avatar_image_filename = None avatar_image_filename = None
for im_format, mime_type in image_formats.items(): for im_format, mime_type in image_formats.items():
@ -1130,7 +1131,7 @@ def _is_attached_image(attachment_filename: str) -> bool:
if '.' not in attachment_filename: if '.' not in attachment_filename:
return False return False
image_ext = ( image_ext = (
'png', 'jpg', 'jpeg', 'webp', 'avif', 'svg', 'gif', 'jxl' 'png', 'jpg', 'jpeg', 'webp', 'avif', 'heic', 'svg', 'gif', 'jxl'
) )
ext = attachment_filename.split('.')[-1] ext = attachment_filename.split('.')[-1]
if ext in image_ext: if ext in image_ext: