forked from MarseyWorld/MarseyWorld
crgd is a king
parent
3c691595e5
commit
386db76c10
|
@ -472,17 +472,17 @@ class Submission(Base):
|
|||
@property
|
||||
@lazy
|
||||
def is_video(self):
|
||||
return self.url and any((self.url.lower().endswith(x) for x in ('.mp4','.webm','.mov'))) and embed_fullmatch_regex.fullmatch(self.url)
|
||||
return self.url and any((self.url.lower().endswith(x) for x in ('.mp4','.webm','.mov'))) and is_safe_url(self.url)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_audio(self):
|
||||
return self.url and any((self.url.lower().endswith(x) for x in ('.mp3','.wav','.ogg','.aac','.m4a','.flac'))) and embed_fullmatch_regex.fullmatch(self.url)
|
||||
return self.url and any((self.url.lower().endswith(x) for x in ('.mp3','.wav','.ogg','.aac','.m4a','.flac'))) and is_safe_url(self.url)
|
||||
|
||||
@property
|
||||
@lazy
|
||||
def is_image(self):
|
||||
if self.url and (self.url.lower().endswith('.webp') or self.url.lower().endswith('.jpg') or self.url.lower().endswith('.png') or self.url.lower().endswith('.gif') or self.url.lower().endswith('.jpeg') or self.url.lower().endswith('?maxwidth=9999') or self.url.lower().endswith('&fidelity=high')) and (self.url.startswith('/') or self.url.startswith(f'{SITE_FULL}/') or embed_fullmatch_regex.fullmatch(self.url)):
|
||||
if self.url and (self.url.lower().endswith('.webp') or self.url.lower().endswith('.jpg') or self.url.lower().endswith('.png') or self.url.lower().endswith('.gif') or self.url.lower().endswith('.jpeg') or self.url.lower().endswith('?maxwidth=9999') or self.url.lower().endswith('&fidelity=high')) and is_safe_url(self.url):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ from files.__main__ import db_session
|
|||
from files.classes.sub import Sub
|
||||
from files.classes.marsey import Marsey
|
||||
from flask import request
|
||||
import tldextract
|
||||
|
||||
SITE = environ.get("DOMAIN", '').strip()
|
||||
SITE_NAME = environ.get("SITE_NAME", '').strip()
|
||||
|
@ -875,7 +876,7 @@ proxies = {"http":"http://127.0.0.1:18080","https":"http://127.0.0.1:18080"}
|
|||
|
||||
blackjack = environ.get("BLACKJACK", "").strip()
|
||||
|
||||
approved_embed_hosts = [
|
||||
approved_embed_hosts = {
|
||||
SITE,
|
||||
'rdrama.net',
|
||||
'pcmemes.net',
|
||||
|
@ -935,14 +936,17 @@ approved_embed_hosts = [
|
|||
'typekit.net',
|
||||
'postimg.cc',
|
||||
'archive.org'
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def is_safe_url(url):
|
||||
return '\\' not in url and (url.startswith('/') or tldextract.extract(url).registered_domain in approved_embed_hosts)
|
||||
|
||||
|
||||
hosts = "|".join(approved_embed_hosts).replace('.','\.')
|
||||
|
||||
image_check_regex = re.compile(f'!\[\]\(((?!(https:\/\/([a-z0-9-]+\.)*({hosts})\/|\/)).*?)\)', flags=re.A)
|
||||
|
||||
embed_fullmatch_regex = re.compile(f'https:\/\/([a-z0-9-]+\.)*({hosts})\/[\w:~,()\-.#&\/=?@%;+]*', flags=re.A)
|
||||
|
||||
video_sub_regex = re.compile(f'(<p>[^<]*)(https:\/\/([a-z0-9-]+\.)*({hosts})\/[\w:~,()\-.#&\/=?@%;+]*?\.(mp4|webm|mov))', flags=re.A)
|
||||
audio_sub_regex = re.compile(f'(<p>[^<]*)(https:\/\/([a-z0-9-]+\.)*({hosts})\/[\w:~,()\-.#&\/=?@%;+]*?\.(mp3|wav|ogg|aac|m4a|flac))', flags=re.A)
|
||||
|
||||
|
|
|
@ -53,16 +53,13 @@ def allowed_attributes(tag, name, value):
|
|||
return False
|
||||
|
||||
if tag == 'a':
|
||||
if name == 'href': return True
|
||||
if name == 'href' and '\\' not in value: return True
|
||||
if name == 'rel' and value == 'nofollow noopener noreferrer': return True
|
||||
if name == 'target' and value == '_blank': return True
|
||||
return False
|
||||
|
||||
if tag == 'img':
|
||||
if name in ['src','data-src']:
|
||||
if value.startswith('/') or value.startswith(f'{SITE_FULL}/') or embed_fullmatch_regex.fullmatch(value): return True
|
||||
else: return False
|
||||
|
||||
if name in ['src','data-src']: return is_safe_url(value)
|
||||
if name == 'loading' and value == 'lazy': return True
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name in ['g','b'] and not value: return True
|
||||
|
@ -81,13 +78,12 @@ def allowed_attributes(tag, name, value):
|
|||
return False
|
||||
|
||||
if tag == 'source':
|
||||
if name == 'src' and embed_fullmatch_regex.fullmatch(value): return True
|
||||
return False
|
||||
if name == 'src': return is_safe_url(value)
|
||||
|
||||
if tag == 'audio':
|
||||
if name == 'src': return is_safe_url(value)
|
||||
if name == 'controls' and value == '': return True
|
||||
if name == 'preload' and value == 'none': return True
|
||||
if name == 'src' and embed_fullmatch_regex.fullmatch(value): return True
|
||||
return False
|
||||
|
||||
if tag == 'p':
|
||||
|
@ -349,7 +345,7 @@ def sanitize(sanitized, alert=False, comment=False, edit=False):
|
|||
def allowed_attributes_emojis(tag, name, value):
|
||||
|
||||
if tag == 'img':
|
||||
if name == 'src' and value.startswith('/'): return True
|
||||
if name == 'src' and value.startswith('/') and '\\' not in value: return True
|
||||
if name == 'loading' and value == 'lazy': return True
|
||||
if name == 'data-bs-toggle' and value == 'tooltip': return True
|
||||
if name == 'g' and not value: return True
|
||||
|
|
|
@ -660,6 +660,8 @@ def badge_grant_post(v):
|
|||
if desc: new_badge.description = desc
|
||||
|
||||
url = request.values.get("url")
|
||||
if '\\' in url: abort(400)
|
||||
|
||||
if url: new_badge.url = url
|
||||
|
||||
g.db.add(new_badge)
|
||||
|
|
|
@ -72,5 +72,5 @@ def allow_nsfw():
|
|||
redir = request.values.get("redir")
|
||||
if redir:
|
||||
if redir.startswith(f'{SITE_FULL}/'): return redirect(redir)
|
||||
if redir.startswith('/'): return redirect(f'{SITE_FULL}{redir}')
|
||||
if redir.startswith('/') and '\\' not in redir: return redirect(f'{SITE_FULL}{redir}')
|
||||
return redirect('/')
|
|
@ -11,11 +11,11 @@ def login_get(v):
|
|||
redir = request.values.get("redirect")
|
||||
if redir:
|
||||
redir = redir.replace("/logged_out", "").strip()
|
||||
if not redir.startswith(f'{SITE_FULL}/') and not redir.startswith('/'): redir = None
|
||||
if not redir.startswith(f'{SITE_FULL}/') and not (redir.startswith('/') and '\\' not in redir): redir = None
|
||||
|
||||
if v and redir:
|
||||
if redir.startswith(f'{SITE_FULL}/'): return redirect(redir)
|
||||
elif redir.startswith('/'): return redirect(f'{SITE_FULL}{redir}')
|
||||
elif redir.startswith('/') and '\\' not in redir: return redirect(f'{SITE_FULL}{redir}')
|
||||
|
||||
return render_template("login.html", failed=False, redirect=redir)
|
||||
|
||||
|
@ -150,11 +150,11 @@ def login_post():
|
|||
redir = request.values.get("redirect")
|
||||
if redir:
|
||||
redir = redir.replace("/logged_out", "").strip()
|
||||
if not redir.startswith(f'{SITE_FULL}/') and not redir.startswith('/'): redir = '/'
|
||||
if not redir.startswith(f'{SITE_FULL}/') and not (redir.startswith('/') and '\\' not in redir): redir = '/'
|
||||
|
||||
if redir:
|
||||
if redir.startswith(f'{SITE_FULL}/'): return redirect(redir)
|
||||
if redir.startswith('/'): return redirect(f'{SITE_FULL}{redir}')
|
||||
if redir.startswith('/') and '\\' not in redir: return redirect(f'{SITE_FULL}{redir}')
|
||||
return redirect('/')
|
||||
|
||||
@app.get("/me")
|
||||
|
|
|
@ -585,7 +585,7 @@ def thumbnail_thread(pid):
|
|||
return f"https://{fragment_url.split('https://')[1]}"
|
||||
elif fragment_url.startswith('//'):
|
||||
return f"https:{fragment_url}"
|
||||
elif fragment_url.startswith('/'):
|
||||
elif fragment_url.startswith('/') and '\\' not in url:
|
||||
parsed_url = urlparse(post_url)
|
||||
return f"https://{parsed_url.netloc}{fragment_url}"
|
||||
else:
|
||||
|
@ -601,7 +601,8 @@ def thumbnail_thread(pid):
|
|||
|
||||
fetch_url = post.url
|
||||
|
||||
if fetch_url.startswith('/'): fetch_url = f"{SITE_FULL}{fetch_url}"
|
||||
if fetch_url.startswith('/') and '\\' not in url:
|
||||
fetch_url = f"{SITE_FULL}{fetch_url}"
|
||||
|
||||
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36"}
|
||||
|
||||
|
@ -854,9 +855,11 @@ def api_is_repost():
|
|||
@auth_required
|
||||
def submit_post(v, sub=None):
|
||||
|
||||
title = request.values.get("title", "").strip()[:500].replace('','')
|
||||
|
||||
url = request.values.get("url", "").strip()
|
||||
|
||||
if '\\' in url: abort(400)
|
||||
|
||||
title = request.values.get("title", "").strip()[:500].replace('','')
|
||||
|
||||
body = request.values.get("body", "").strip().replace('','')
|
||||
|
||||
|
@ -1516,7 +1519,7 @@ def api_pin_post(post_id, v):
|
|||
def get_post_title(v):
|
||||
|
||||
url = request.values.get("url")
|
||||
if not url: abort(400)
|
||||
if not url or '\\' in url: abort(400)
|
||||
|
||||
try: x = requests.get(url, headers=titleheaders, timeout=5, proxies=proxies)
|
||||
except: abort(400)
|
||||
|
|
|
@ -641,9 +641,8 @@ def settings_profilecss(v):
|
|||
urls = list(css_regex.finditer(profilecss)) + list(css_regex2.finditer(profilecss))
|
||||
for i in urls:
|
||||
url = i.group(1)
|
||||
if url.startswith('/'): continue
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
if domain not in approved_embed_hosts:
|
||||
if not is_safe_url(url):
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
error = f"The domain '{domain}' is not allowed, please use one of these domains\n\n{approved_embed_hosts}."
|
||||
return render_template("settings_profilecss.html", error=error, v=v)
|
||||
|
||||
|
|
|
@ -341,9 +341,8 @@ def post_sub_css(v, sub):
|
|||
urls = list(css_regex.finditer(css)) + list(css_regex2.finditer(css))
|
||||
for i in urls:
|
||||
url = i.group(1)
|
||||
if url.startswith('/'): continue
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
if domain not in approved_embed_hosts:
|
||||
if not is_safe_url(url):
|
||||
domain = tldextract.extract(url).registered_domain
|
||||
error = f"The domain '{domain}' is not allowed, please use one of these domains\n\n{approved_embed_hosts}."
|
||||
return render_template('sub/settings.html', v=v, sidebar=sub.sidebar, sub=sub, error=error)
|
||||
|
||||
|
|
Loading…
Reference in New Issue