Compare commits
7 Commits
2320ddb90f
...
f47f2153e1
Author | SHA1 | Date | |
---|---|---|---|
f47f2153e1 | |||
bf74135798 | |||
cb406d7a2e | |||
a59c6abca0 | |||
b2b571dcf7 | |||
285d2ce490 | |||
cbf463e67a |
@ -159,6 +159,8 @@ class Comment(admin.Administerable):
|
||||
del f['captcha_passed']
|
||||
del f['moderation_passed']
|
||||
|
||||
f['text'].id = f'comment-reply-{self.id}-text' # avoid id collision for help toggle
|
||||
|
||||
return f
|
||||
|
||||
@app.abstract
|
||||
|
@ -21,7 +21,7 @@ def db_connect():
|
||||
app.db.connect(reuse_if_open=True)
|
||||
app.db.set_time_zone('UTC')
|
||||
|
||||
except peewee.OperationalError as e:
|
||||
except (peewee.OperationalError, peewee.InterfaceError) as e:
|
||||
app.logger.error(f"Error connecting to database: {str(e)}")
|
||||
|
||||
class ModelMeta(peewee.ModelBase, util.ChildAwareMeta):
|
||||
|
2
form.py
2
form.py
@ -65,7 +65,7 @@ class TimeParamType(types.ParamType):
|
||||
if hour < 0 or hour > 24:
|
||||
self.fail(f"Hour out of range for time input: {hour}, must be between 0 and 24", param, ctx)
|
||||
|
||||
if hour == 24 and minute > 0:
|
||||
if hour >= 24 and minute > 0:
|
||||
self.fail(f"Time input past 24:00: '{value}'", param, ctx)
|
||||
|
||||
if minute < 0 or minute > 59:
|
||||
|
17
main.py
17
main.py
@ -40,6 +40,8 @@ def error_catchall(e):
|
||||
if app.debug:
|
||||
raise
|
||||
|
||||
app.logger.error(e)
|
||||
|
||||
@rendering.page(title_show=False)
|
||||
def errorpage():
|
||||
|
||||
@ -557,7 +559,7 @@ class ScoredLink(admin.Administerable):
|
||||
How many **third-party sites** the linked page loads data from.
|
||||
|
||||
This is relevant to your privacy because each of those third-party sites
|
||||
gets – at the very least – to see that you visited this page.
|
||||
gets – at the very least – to see that you visited the linked page.
|
||||
|
||||
*Lower* is better, **0** is *ideal*.""")
|
||||
|
||||
@ -574,7 +576,11 @@ gets – at the very least – to see that you visited this page.
|
||||
external_site_count = 0
|
||||
url_domain = self.url.split('/')[2]
|
||||
|
||||
html = requests.get(self.url, timeout=30).text
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36', # such stealth, many agent
|
||||
}
|
||||
|
||||
html = requests.get(self.url, timeout=30, headers=headers).text
|
||||
dom = bs4.BeautifulSoup(html, 'lxml')
|
||||
|
||||
scored_elements = {
|
||||
@ -584,6 +590,8 @@ gets – at the very least – to see that you visited this page.
|
||||
'object': 'data'
|
||||
}
|
||||
|
||||
external_domains = set()
|
||||
|
||||
for tag, attribute in scored_elements.items():
|
||||
|
||||
for element in dom.find_all(tag):
|
||||
@ -597,9 +605,10 @@ gets – at the very least – to see that you visited this page.
|
||||
|
||||
if attribute_domain != url_domain and\
|
||||
not attribute_domain.endswith(f'.{url_domain}'): # not a subdomain of url_domain
|
||||
external_site_count += 1
|
||||
#external_site_count += 1
|
||||
external_domains.add(attribute_domain)
|
||||
|
||||
self.external_site_count = external_site_count
|
||||
self.external_site_count = len(external_domains)
|
||||
self.last_scrape = datetime.datetime.utcnow()
|
||||
self.save()
|
||||
|
||||
|
@ -213,8 +213,6 @@ def section_core_rule(state):
|
||||
elif token.type != 'heading_open':
|
||||
tokens.append(markdown_it.token.Token('section_open', 'section', 1))
|
||||
nesting += 1
|
||||
else:
|
||||
open_next = True
|
||||
|
||||
elif token.type == 'heading_open' and token.tag == 'h2':
|
||||
|
||||
|
19
rendering.py
19
rendering.py
@ -36,10 +36,14 @@ def page(**template_params):
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
|
||||
agent = flask.request.headers.get('User-Agent')
|
||||
|
||||
params = {
|
||||
'site_name': app.config['SITE_NAME'],
|
||||
'user': flask.g.user,
|
||||
'tls_cipher': flask.g.tls_cipher,
|
||||
'client_ua': agent,
|
||||
'client_ua_noadblock': agent_noadblock(agent),
|
||||
'client_cert_verified': flask.g.client_cert_verified,
|
||||
'client_cert_fingerprint': flask.g.client_cert_fingerprint,
|
||||
'client_cert_fingerprint_matched': flask.g.client_cert_fingerprint_matched,
|
||||
@ -153,6 +157,21 @@ def page(**template_params):
|
||||
|
||||
return decorator
|
||||
|
||||
noadblock_progs = [
|
||||
re.compile('.*Android.*Chrome\/'), # no built-in adblocker, can't install extensions
|
||||
]
|
||||
|
||||
def agent_noadblock(agent):
|
||||
|
||||
# Determine whether the given user agent has no ability to add an adblocker.
|
||||
|
||||
for prog in noadblock_progs:
|
||||
|
||||
if prog.match(agent):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@app.template_test('renderable')
|
||||
def test_renderable(obj):
|
||||
return isinstance(obj, Renderable)
|
||||
|
@ -290,7 +290,6 @@ html {
|
||||
}
|
||||
|
||||
html, body {
|
||||
min-width: 100vw;
|
||||
min-height: 100vh;
|
||||
max-width: 100vw;
|
||||
}
|
||||
@ -329,6 +328,7 @@ body > header {
|
||||
}
|
||||
|
||||
.security-info span {
|
||||
display: block;
|
||||
font-size: 70%;
|
||||
color: var(--color-highlight-inactive);
|
||||
}
|
||||
@ -400,25 +400,11 @@ main > .tabs:has(a:focus) {
|
||||
|
||||
main > h1 {
|
||||
display: block;
|
||||
width: var(--distance-typographic-width);
|
||||
width: 100%;
|
||||
max-width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* deleteme */
|
||||
article > section {
|
||||
margin: var(--distance-major) 0;
|
||||
background-size: 100%;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
article > section > .content {
|
||||
background: hsla(0 0 5 / 90%);
|
||||
backdrop-filter: blur(8px);
|
||||
width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
padding: var(--distance-main);
|
||||
} /* /deleteme */
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: var(--font-decorative);
|
||||
font-weight: normal;
|
||||
@ -525,11 +511,45 @@ nav a.trail {
|
||||
|
||||
@media (screen and orientation: portrait), (max-width: 100rem) {
|
||||
|
||||
body > header,
|
||||
body > footer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body > header .security-info {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body > header .seal-message {
|
||||
position: relative;
|
||||
right: initial;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
body > footer > * {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
body > footer menu {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
body > footer menu a {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body > footer object,
|
||||
body > footer img {
|
||||
max-width: 80vw !important;
|
||||
}
|
||||
|
||||
body > .menus {
|
||||
/* this element (currently) contains all burgered content */
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: calc(100vw - var(--menu-burger-width));
|
||||
/*left: calc(100vw - var(--menu-burger-width));*/
|
||||
left: calc(100% - var(--menu-burger-width));
|
||||
top: 10rem;
|
||||
background: transparent;
|
||||
backdrop-filter: none;
|
||||
@ -545,7 +565,7 @@ nav a.trail {
|
||||
|
||||
.with-burger .burgers + * { /* element following .burgers */
|
||||
position: fixed;
|
||||
width: calc(100vw - 4rem);
|
||||
width: calc(100% - var(--menu-burger-width));
|
||||
min-height: 25vh;
|
||||
left: -100vw;
|
||||
top: 0;
|
||||
@ -647,6 +667,11 @@ body > footer menu {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body > footer object,
|
||||
body > footer img {
|
||||
max-width: 20%;
|
||||
}
|
||||
|
||||
body > footer menu li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -714,6 +739,7 @@ article.errorpage {
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
width: 40rem;
|
||||
max-width: 100%;
|
||||
min-height: 10rem;
|
||||
margin: 0 auto;
|
||||
padding: var(--distance-main);
|
||||
@ -851,12 +877,12 @@ a.download:active {
|
||||
overflow: auto;
|
||||
z-index: 2000;
|
||||
min-width: 100vw;
|
||||
/*backdrop-filter: blur(8px); */ /* breaks fixed for a[href="#close"] */
|
||||
/*backdrop-filter: blur(8px); */ /* breaks fixed for a[href="#__close"] */
|
||||
/* see: https://stackoverflow.com/a/1384613 */
|
||||
background: var(--color-bg-alt);
|
||||
}
|
||||
|
||||
.modal a[href="#close"] {
|
||||
.modal a[href="#__close"] {
|
||||
display: block;
|
||||
position: fixed;
|
||||
z-index: 2100;
|
||||
@ -872,7 +898,7 @@ a.download:active {
|
||||
|
||||
}
|
||||
|
||||
.modal a[href="#close"]:hover {
|
||||
.modal a[href="#__close"]:hover {
|
||||
color: var(--color-error);
|
||||
}
|
||||
|
||||
@ -931,7 +957,7 @@ a.download:active {
|
||||
}
|
||||
|
||||
.toggle-input:checked + .toggle-label + * {
|
||||
max-height: 100vh;
|
||||
max-height: 500vh;
|
||||
}
|
||||
|
||||
/* comments */
|
||||
@ -1156,7 +1182,7 @@ article.renderable > .content > h3,
|
||||
article.renderable > .content > h4,
|
||||
article.renderable > .content > h5,
|
||||
article.renderable > .content > h6 {
|
||||
width: var(--distance-typographic-width);
|
||||
max-width: var(--distance-typographic-width);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@ -1592,6 +1618,7 @@ body > .menus .searchminiform .field-help-wrapper {
|
||||
|
||||
.propaganda .claim {
|
||||
width: var(--distance-typographic-width);
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@ -1620,6 +1647,7 @@ body > .menus .searchminiform .field-help-wrapper {
|
||||
|
||||
.propagandapiece .files {
|
||||
width: var(--distance-typographic-width);
|
||||
max-width: 100%;
|
||||
padding: var(--distance-main);
|
||||
margin: var(--distance-main) auto;
|
||||
}
|
||||
@ -1734,6 +1762,7 @@ fieldset.propagandapiece-wrapper > .fields > .form-order > .buttons {
|
||||
display: block;
|
||||
min-width: var(--distance-typographic-width);
|
||||
width: var(--distance-typographic-width);
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@ -1799,6 +1828,7 @@ fieldset.propagandapiece-wrapper > .fields > .form-order > .buttons {
|
||||
.propagandapieceitemform > .fields > .field-order_pos > label {
|
||||
display: block;
|
||||
width: var(--distance-typographic-width);
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
@ -6,15 +6,17 @@
|
||||
height: 100vh;
|
||||
background: var(--color-bg-alt);
|
||||
backdrop-filter: blur(8px);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.ad .content {
|
||||
max-width: 80rem;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.ad .moji {
|
||||
font-size: 30rem;
|
||||
font-size: 33vh;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@ -29,3 +31,17 @@
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ad ul {
|
||||
max-width: 80ex;
|
||||
margin: 0 auto;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.ad ul li {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.ad ul .adblocker-description {
|
||||
padding-left: 2rem;
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
<header>
|
||||
|
||||
<div class="security-info">
|
||||
{% if client_ua %}
|
||||
<span class="client-ua">{{ client_ua }}</span>
|
||||
{% endif %}
|
||||
{% if tls_cipher %}
|
||||
<span class="tls-cipher">{{ tls_cipher }}</span>
|
||||
{% endif %}
|
||||
@ -111,8 +114,34 @@
|
||||
<div class="ad native-ad native-ad-1 ytd-j yxd-j yxd-jd aff-content-col aff-inner-col aff-item-list ark-ad-message inplayer-ad inplayer_banners in_stream_banner trafficjunky-float-right dbanner preroll-blocker happy-inside-player blocker-notice blocker-overlay exo-horizontal ave-pl bottom-hor-block brs-block advboxemb wgAdBlockMessage glx-watermark-container overlay-advertising-new header-menu-bottom-ads rkads mdp-deblocker-wrapper amp-ad-inner imggif bloc-pub bloc-pub2 hor_banner aan_fake aan_fake__video-units rps_player_ads fints-block__row full-ave-pl full-bns-block vertbars video-brs player-bns-block wps-player__happy-inside gallery-bns-bl stream-item-widget adsbyrunactive happy-under-player adde_modal_detector adde_modal-overlay ninja-recommend-block aoa_overlay">
|
||||
<div class="content">
|
||||
<div class="moji">⚠</div>
|
||||
{% if client_ua_noadblock %}
|
||||
<span class="fake-header">Your browser is so shite, you can't install an adblocker.</span>
|
||||
<span class="fake-subheader">This is a major security risk. Install a less shit one and then an adblocker. <a href="https://getfirefox.com/" rel="noreferrer">Firefox</a> is the <em>least</em> shit one.</span>
|
||||
{% else %}
|
||||
<span class="fake-header">You don't seem to have an adblocker installed.</span>
|
||||
<span class="fake-subheader">Go install one now. We recommend <a href="https://adnauseam.io/" target="_blank" rel="noreferrer">AdNauseam</a>.</span>
|
||||
<span class="fake-subheader">Go install one now. We recommend one of these, they're all <em>free & open source</em>:</span>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://adnauseam.io/" target="_blank" rel="noreferrer">AdNauseam</a>
|
||||
<div class="adblocker-description">
|
||||
The best one, weaponizes simulated ad clicks against advertisers.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://ublockorigin.com/" target="_blank" rel="noreferrer">uBlock Origin</a>
|
||||
<div class="adblocker-description">
|
||||
The basis for AdNauseam, all the same features – minus the weaponization.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://ublockorigin.com/" target="_blank" rel="noreferrer">uBlock Origin Lite</a>
|
||||
<div class="adblocker-description">
|
||||
Crippled by <a href="https://en.wikipedia.org/wiki/Google_Chrome#Manifest_V3_2" target="_blank" rel="noreferrer">Manifest v3</a>.
|
||||
Activate the 'complete' filtering mode to proceed, but think about upgrading to <a href="https://getfirefox.com/" target="_blank" rel="noreferrer">Firefox</a>.
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
<div id="gallery-{{ content.name }}" class="modal">
|
||||
|
||||
<a href="#close">✖</a>
|
||||
<a href="#__close">✖</a>
|
||||
|
||||
{% for item in content.items_ordered %}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{% extends 'default/templates/renderable/upload.html' %}
|
||||
|
||||
{% block fileview %}
|
||||
<a href="#modal-image-{{ content.id }}">
|
||||
<a href="#modal-image-{{ content.name }}">
|
||||
<div class="preview">
|
||||
<img
|
||||
src="{{ content.url('raw') }}"
|
||||
@ -12,8 +12,8 @@
|
||||
/>
|
||||
</div>
|
||||
</a>
|
||||
<div id="modal-image-{{ content.id }}" class="modal">
|
||||
<a href="#close">✖</a>
|
||||
<div id="modal-image-{{ content.name }}" class="modal">
|
||||
<a href="#__close">✖</a>
|
||||
<div class="content">
|
||||
<img
|
||||
src="{{ content.url('raw') }}"
|
||||
|
Loading…
Reference in New Issue
Block a user