tighten CSP

pull/83/head
Aevann 2022-12-27 03:22:39 +02:00
parent 35d9d7c3bc
commit 6114111654
46 changed files with 182 additions and 163 deletions

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const CACHE_NAME = "offlineCache-v1"; const CACHE_NAME = "offlineCache-v1";
const OFFLINE_URL = "/assets/offline.html"; const OFFLINE_URL = "/offline.html";
self.addEventListener("install", () => { self.addEventListener("install", () => {
const cacheOfflinePage = async () => { const cacheOfflinePage = async () => {

View File

@ -13,26 +13,30 @@ def session_init():
@app.before_request @app.before_request
def before_request(): def before_request():
g.desires_auth = False
if not IS_LOCALHOST:
app.config["COOKIE_DOMAIN"] = f".{request.host}"
app.config["SESSION_COOKIE_DOMAIN"] = app.config["COOKIE_DOMAIN"]
if SITE == 'marsey.world' and request.path != '/kofi':
abort(404)
g.agent = request.headers.get("User-Agent", "")
if not g.agent and request.path != '/kofi':
return 'Please use a "User-Agent" header!', 403
ua = g.agent.lower()
if request.host != SITE: if request.host != SITE:
abort(403, "Unauthorized host provided!") abort(403, "Unauthorized host provided!")
if SITE == 'marsey.world' and request.path != '/kofi':
abort(404)
if request.headers.get("CF-Worker"): if request.headers.get("CF-Worker"):
abort(403, "Cloudflare workers are not allowed to access this website.") abort(403, "Cloudflare workers are not allowed to access this website.")
if not get_setting('bots') and request.headers.get("Authorization"): abort(403) g.agent = request.headers.get("User-Agent", "")
if not g.agent and request.path != '/kofi':
abort(403, 'Please use a "User-Agent" header!')
if not get_setting('bots') and request.headers.get("Authorization"):
abort(403)
g.desires_auth = False
if not IS_LOCALHOST:
app.config["COOKIE_DOMAIN"] = f".{request.host}"
app.config["SESSION_COOKIE_DOMAIN"] = app.config["COOKIE_DOMAIN"]
ua = g.agent.lower()
g.nonce = None
if '; wv) ' in ua: if '; wv) ' in ua:
g.browser = 'webview' g.browser = 'webview'
@ -54,11 +58,57 @@ def before_request():
limiter.check() limiter.check()
g.db = db_session() g.db = db_session()
CSP = {
"upgrade-insecure-requests": "",
"default-src": "'none'",
"frame-ancestors": "'none'",
"form-action": "'self'",
"manifest-src": "'self'",
"worker-src": "'self'",
"base-uri": "'self'",
"font-src": "'self'",
"media-src": "'self'",
"style-src-elem": "'self' 'nonce-{nonce}'",
"style-src-attr": "'unsafe-inline'",
"style-src": "'self' 'unsafe-inline'",
"script-src-elem": "'self' 'nonce-{nonce}' challenges.cloudflare.com",
"script-src-attr": "'unsafe-inline'",
"script-src": "'self' 'unsafe-inline' challenges.cloudflare.com",
"img-src": "https:",
"frame-src": "challenges.cloudflare.com www.youtube-nocookie.com platform.twitter.com",
"connect-src": "'self' tls-use1.fpapi.io api.fpjs.io",
"report-to": "csp",
"report-uri": "/csp_violations",
}
if IS_LOCALHOST:
CSP["style-src-elem"] += " rdrama.net"
CSP["script-src-elem"] += " rdrama.net"
CSP["img-src"] += " http:"
CSP_str = ''
for k, val in CSP.items():
CSP_str += f'{k} {val}; '
@app.after_request @app.after_request
def after_request(response:Response): def after_request(response:Response):
if response.status_code < 400: if response.status_code < 400:
_set_cloudflare_cookie(response) _set_cloudflare_cookie(response)
_commit_and_close_db() _commit_and_close_db()
if g.nonce:
response.headers.add("Report-To", {"group":"csp","max_age":10886400,"endpoints":[{"url":"/csp_violations"}]})
response.headers.add("Content-Security-Policy", CSP_str.format(nonce=g.nonce))
return response return response

View File

@ -333,3 +333,11 @@ if not os.path.exists(f'files/templates/donate_{SITE_NAME}.html'):
@auth_desired_with_logingate @auth_desired_with_logingate
def donate(v): def donate(v):
return render_template(f'donate_{SITE_NAME}.html', v=v) return render_template(f'donate_{SITE_NAME}.html', v=v)
@app.post('/csp_violations')
@limiter.limit("10/minute;50/day")
def csp_violations():
content = request.get_json(force=True)
print(json.dumps(content, indent=4, sort_keys=True), flush=True)
return ''

View File

@ -1,4 +1,5 @@
import time import time
import secrets
from flask import g, request, session from flask import g, request, session
from files.classes.clients import ClientAuth from files.classes.clients import ClientAuth
@ -40,7 +41,8 @@ def get_logged_in_user():
else: else:
session.pop("lo_user") session.pop("lo_user")
g.is_api_or_xhr = bool((v and v.client) or request.headers.get("xhr")) g.is_api = v and v.client
g.is_api_or_xhr = bool(g.is_api or request.headers.get("xhr"))
if request.method.lower() != "get" and get_setting('read_only_mode') and not (v and v.admin_level >= PERMS['SITE_BYPASS_READ_ONLY_MODE']): if request.method.lower() != "get" and get_setting('read_only_mode') and not (v and v.admin_level >= PERMS['SITE_BYPASS_READ_ONLY_MODE']):
abort(403) abort(403)
@ -67,6 +69,10 @@ def get_logged_in_user():
if f'@{v.username}, ' not in f.read(): if f'@{v.username}, ' not in f.read():
t = time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time())) t = time.strftime("%d/%B/%Y %H:%M:%S UTC", time.gmtime(time.time()))
log_file(f'@{v.username}, {v.truescore}, {ip}, {t}\n', 'eg.log') log_file(f'@{v.username}, {v.truescore}, {ip}, {t}\n', 'eg.log')
if not g.is_api:
g.nonce = secrets.token_urlsafe(16)
return v return v
def auth_desired(f): def auth_desired(f):

View File

@ -66,7 +66,7 @@
</section> </section>
{% endif %} {% endif %}
<script> <script nonce="{{g.nonce}}">
function submitAddAlt(element) { function submitAddAlt(element) {
if (!element || !element.form) return; if (!element || !element.form) return;
const isLinking = element.id == 'add-alt-form-link'; const isLinking = element.id == 'add-alt-form-link';

View File

@ -54,7 +54,7 @@
</form> </form>
<style> <style nonce="{{g.nonce}}">
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
table { table {
display: inline-block; display: inline-block;

View File

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<script> <script nonce="{{g.nonce}}">
function unbanDomain(t, domain) { function unbanDomain(t, domain) {
postToastSwitch(t,'/admin/unban_domain/' + domain); postToastSwitch(t,'/admin/unban_domain/' + domain);
t.parentElement.parentElement.remove(); t.parentElement.parentElement.remove();

View File

@ -50,7 +50,7 @@
{% endif %} {% endif %}
{% if p.award_count("tilt", v) %} {% if p.award_count("tilt", v) %}
<style> <style nonce="{{g.nonce}}">
@keyframes post-tilt { @keyframes post-tilt {
0% {transform: rotate(0deg);} 0% {transform: rotate(0deg);}
25% {transform: rotate({{p.award_count("tilt", v)}}deg);} 25% {transform: rotate({{p.award_count("tilt", v)}}deg);}

View File

@ -1,7 +1,7 @@
{% extends "casino/game_screen.html" %} {% extends "casino/game_screen.html" %}
{% block script %} {% block script %}
<script> <script nonce="{{g.nonce}}">
function makeBlackjackRequest(action) { function makeBlackjackRequest(action) {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open("post", `/casino/twentyone/${action}`); xhr.open("post", `/casino/twentyone/${action}`);
@ -236,7 +236,7 @@
{% endblock %} {% endblock %}
{% block actions %} {% block actions %}
<style> <style nonce="{{g.nonce}}">
.blackjack-cardset { .blackjack-cardset {
position: relative; position: relative;
display: flex; display: flex;

View File

@ -1,7 +1,7 @@
{% extends "default.html" %} {% extends "default.html" %}
{% block pagetitle %}{{game.capitalize()}}{% endblock %} {% block pagetitle %}{{game.capitalize()}}{% endblock %}
{% block content %} {% block content %}
<style> <style nonce="{{g.nonce}}">
.game_screen-title { .game_screen-title {
display: flex; display: flex;
align-items: center; align-items: center;
@ -27,7 +27,7 @@
} }
</style> </style>
<script type="text/javascript"> <script nonce="{{g.nonce}}">
/** /**
* This script block contains generic helper function usable across casino games: * This script block contains generic helper function usable across casino games:
* - Wagers * - Wagers
@ -233,7 +233,7 @@
{% block script %} {% endblock %} {% block script %} {% endblock %}
<style> <style nonce="{{g.nonce}}">
@keyframes drawing { @keyframes drawing {
from { from {
left: 0; left: 0;

View File

@ -1,7 +1,7 @@
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %} {% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
{% block script %} {% block script %}
<script type="text/javascript"> <script nonce="{{g.nonce}}">
if ( if (
document.readyState === "complete" || document.readyState === "complete" ||
(document.readyState !== "loading" && !document.documentElement.doScroll) (document.readyState !== "loading" && !document.documentElement.doScroll)
@ -393,7 +393,7 @@
{% endblock %} {% endblock %}
{% block screen %} {% block screen %}
<style> <style nonce="{{g.nonce}}">
.roulette-table-number { .roulette-table-number {
flex: 1; flex: 1;
height: 60px; height: 60px;

View File

@ -1,7 +1,7 @@
{% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %} {% extends "casino/game_screen.html" %} {% block result %} N/A {% endblock %}
{% block script %} {% block script %}
<script type="text/javascript"> <script nonce="{{g.nonce}}">
function pullSlots() { function pullSlots() {
const { amount, currency } = getWager(); const { amount, currency } = getWager();
@ -73,7 +73,7 @@
{% endblock %} {% endblock %}
{% block screen %} {% block screen %}
<style> <style nonce="{{g.nonce}}">
.slots_reels { .slots_reels {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -17,7 +17,7 @@
data-avatar="{{v.profile_url}}" data-avatar="{{v.profile_url}}"
data-hat="{{v.hat_active(v)[0]}}"> data-hat="{{v.hat_active(v)[0]}}">
</div> </div>
<script>window.global = window</script> <script nonce="{{g.nonce}}">window.global = window</script>
{% if IS_LOCALHOST %} {% if IS_LOCALHOST %}
<script defer src="https://rdrama.net/assets/js/chat_done.js"></script> <script defer src="https://rdrama.net/assets/js/chat_done.js"></script>
{% else %} {% else %}

View File

@ -1,7 +1,7 @@
{%- import 'util/macros.html' as macros with context -%} {%- import 'util/macros.html' as macros with context -%}
{% if not request.headers.get("xhr") %} {% if not request.headers.get("xhr") %}
{% if comment_info %} {% if comment_info %}
<script> <script nonce="{{g.nonce}}">
if (location.hash != 'context') if (location.hash != 'context')
location.hash = 'context' location.hash = 'context'
</script> </script>
@ -246,7 +246,7 @@
{% endif %} {% endif %}
{% if c.award_count("tilt", v) %} {% if c.award_count("tilt", v) %}
<style> <style nonce="{{g.nonce}}">
@keyframes c{{c.id}}-tilt { @keyframes c{{c.id}}-tilt {
0% {transform: rotate(0deg);} 0% {transform: rotate(0deg);}
25% {transform: rotate({{c.award_count("tilt", v)}}deg);} 25% {transform: rotate({{c.award_count("tilt", v)}}deg);}
@ -786,7 +786,7 @@
<script defer src="{{'js/comments+submission_listing.js' | asset}}"></script> <script defer src="{{'js/comments+submission_listing.js' | asset}}"></script>
<script defer src="{{'js/comments.js' | asset}}"></script> <script defer src="{{'js/comments.js' | asset}}"></script>
<script> <script nonce="{{g.nonce}}">
{% if p and (not v or v.highlightcomments) %} {% if p and (not v or v.highlightcomments) %}
comments = JSON.parse(localStorage.getItem("comment-counts")) || {} comments = JSON.parse(localStorage.getItem("comment-counts")) || {}
lastCount = comments['{{p.id}}'] lastCount = comments['{{p.id}}']
@ -852,7 +852,7 @@
{# TODO: disabled pending fix #} {# TODO: disabled pending fix #}
{% if false %} {% if false %}
<div id="detection" style="display:none;background-color:canvas;color-scheme:light"></div> <div id="detection" style="display:none;background-color:canvas;color-scheme:light"></div>
<script> <script nonce="{{g.nonce}}">
const detectionDiv = document.querySelector('#detection'); const detectionDiv = document.querySelector('#detection');
const isAutoDark = getComputedStyle(detectionDiv).backgroundColor != 'rgb(255, 255, 255)'; const isAutoDark = getComputedStyle(detectionDiv).backgroundColor != 'rgb(255, 255, 255)';
if (!isAutoDark) { if (!isAutoDark) {

View File

@ -80,7 +80,7 @@
{% endif %} {% endif %}
{% if g.browser == 'apple' %} {% if g.browser == 'apple' %}
<script> <script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const videos = document.querySelectorAll('video') const videos = document.querySelectorAll('video')

View File

@ -3,8 +3,6 @@
<html> <html>
<head> <head>
<meta name="description" content="{{DESCRIPTION}}"> <meta name="description" content="{{DESCRIPTION}}">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none';">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="x-apple-disable-message-reformatting"> <meta name="x-apple-disable-message-reformatting">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

View File

@ -3,35 +3,8 @@
<head> <head>
<meta name="description" content="People die and this is the place to see it. You only have one life, don't make the mistakes seen here."> <meta name="description" content="People die and this is the place to see it. You only have one life, don't make the mistakes seen here.">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none';"> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; font-src 'self'; img-src 'self';">
<style>
:root{--primary:#ff66ac}
.mod:before {
content: "(((";
}
.mod:after {
content: ")))";
}
body {
padding-top: 54px !important;
}
@media (max-width: 767.98px) {
body {
padding-top: 44px !important;
}
}
@media (min-width: 380px) {
#logo {
width: 100px;
margin-left: 0.5rem !important;
}
}
.pad {
padding-bottom: 7.4px;
padding-top: 7.4px;
}
</style>
<link rel="stylesheet" href="/assets/css/main.css?v=4032"> <link rel="stylesheet" href="/assets/css/main.css?v=4032">
<link rel="stylesheet" href="/assets/css/midnight.css?v=4000"> <link rel="stylesheet" href="/assets/css/midnight.css?v=4000">
@ -50,7 +23,6 @@
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="apple-touch-icon" sizes="180x180" href="/icon.webp?v=1"> <link rel="apple-touch-icon" sizes="180x180" href="/icon.webp?v=1">
<link rel="manifest" href="/assets/manifest_WPD.json?v=426">
<link rel="mask-icon" href="/icon.webp?v=1"> <link rel="mask-icon" href="/icon.webp?v=1">
<link rel="shortcut icon" href="/icon.webp?v=1"> <link rel="shortcut icon" href="/icon.webp?v=1">
<meta name="apple-mobile-web-app-title" content="WPD"> <meta name="apple-mobile-web-app-title" content="WPD">
@ -93,7 +65,7 @@
<nav class="shadow-md fixed-top"> <nav class="shadow-md fixed-top">
<div class="navbar navbar-expand-md navbar-light" id="navbar"> <div class="navbar navbar-expand-md navbar-light" id="navbar">
<div class="container-fluid" style="padding: 0;"> <div class="container-fluid p-0">
<a href="/" class="navbar-brand mr-auto"> <a href="/" class="navbar-brand mr-auto">
<img id="header--icon" alt="header icon" src="/i/WPD/headericon.webp?v=3009"> <img id="header--icon" alt="header icon" src="/i/WPD/headericon.webp?v=3009">
</a> </a>
@ -105,10 +77,10 @@
</div> </div>
<div class="flex-grow-1 d-fl d-mob-none pad"> <div class="flex-grow-1 d-fl d-mob-none pad">
<form class="form-inline search flex-nowrap mx-0 mx-lg-auto" style="margin-right: 40rem !important;" action="/search/posts/" method="get"> <form class="form-inline search flex-nowrap mx-0 mx-lg-auto" action="/search/posts/" method="get">
<input autocomplete="off" class="form-control w-100" type="search" placeholder="Search" name="q" value=""> <input autocomplete="off" class="form-control w-100" type="search" placeholder="Search" name="q" value="">
<span class="input-group-append"> <span class="input-group-append">
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem;"> <span class="input-group-text border-0 bg-transparent">
<i class="fa fa-search"></i> <i class="fa fa-search"></i>
</span> </span>
</span> </span>

View File

@ -3,35 +3,8 @@
<head> <head>
<meta name="description" content="rdrama.net caters to drama in all forms such as: Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn&#39;t drama we won&#39;t touch, and we want it all!"> <meta name="description" content="rdrama.net caters to drama in all forms such as: Real life, videos, photos, gossip, rumors, news sites, Reddit, and Beyond™. There isn&#39;t drama we won&#39;t touch, and we want it all!">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; connect-src 'self'; object-src 'none';"> <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self'; font-src 'self'; img-src 'self';">
<style>
:root{--primary:#ff66ac}
.mod:before {
content: "(((";
}
.mod:after {
content: ")))";
}
body {
padding-top: 54px !important;
}
@media (max-width: 767.98px) {
body {
padding-top: 44px !important;
}
}
@media (min-width: 380px) {
#logo {
width: 100px;
margin-left: 0.5rem !important;
}
}
.pad {
padding-bottom: 7.4px;
padding-top: 7.4px;
}
</style>
<link rel="stylesheet" href="/assets/css/main.css?v=4032"> <link rel="stylesheet" href="/assets/css/main.css?v=4032">
<link rel="stylesheet" href="/assets/css/midnight.css?v=4000"> <link rel="stylesheet" href="/assets/css/midnight.css?v=4000">
@ -50,7 +23,6 @@
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="apple-touch-icon" sizes="180x180" href="/icon.webp?v=1"> <link rel="apple-touch-icon" sizes="180x180" href="/icon.webp?v=1">
<link rel="manifest" href="/assets/manifest_rDrama.json?v=426">
<link rel="mask-icon" href="/icon.webp?v=1"> <link rel="mask-icon" href="/icon.webp?v=1">
<link rel="shortcut icon" href="/icon.webp?v=1"> <link rel="shortcut icon" href="/icon.webp?v=1">
<meta name="apple-mobile-web-app-title" content="rDrama"> <meta name="apple-mobile-web-app-title" content="rDrama">
@ -93,7 +65,7 @@
<nav class="shadow-md fixed-top"> <nav class="shadow-md fixed-top">
<div class="navbar navbar-expand-md navbar-light" id="navbar"> <div class="navbar navbar-expand-md navbar-light" id="navbar">
<div class="container-fluid" style="padding: 0;"> <div class="container-fluid p-0">
<a href="/" class="navbar-brand mr-auto"> <a href="/" class="navbar-brand mr-auto">
<img id="header--icon" alt="header icon" src="/i/rDrama/headericon.webp?v=3009"> <img id="header--icon" alt="header icon" src="/i/rDrama/headericon.webp?v=3009">
</a> </a>
@ -105,10 +77,10 @@
</div> </div>
<div class="flex-grow-1 d-fl d-mob-none pad"> <div class="flex-grow-1 d-fl d-mob-none pad">
<form class="form-inline search flex-nowrap mx-0 mx-lg-auto" style="margin-right: 40rem !important;" action="/search/posts/" method="get"> <form class="form-inline search flex-nowrap mx-0 mx-lg-auto" action="/search/posts/" method="get">
<input autocomplete="off" class="form-control w-100" type="search" placeholder="Search" name="q" value=""> <input autocomplete="off" class="form-control w-100" type="search" placeholder="Search" name="q" value="">
<span class="input-group-append"> <span class="input-group-append">
<span class="input-group-text border-0 bg-transparent" style="margin-left: -2.5rem;"> <span class="input-group-text border-0 bg-transparent">
<i class="fa fa-search"></i> <i class="fa fa-search"></i>
</span> </span>
</span> </span>

View File

@ -9,19 +9,19 @@
{# idk why snow isn't working vvvvvvvvvv #} {# idk why snow isn't working vvvvvvvvvv #}
{% if p.award_count("snow", v) %} {% if p.award_count("snow", v) %}
<script src="{{'event/js/snow.js'|asset}}"></script> <script src="{{'event/js/snow.js'|asset}}"></script>
<script>snow(80);</script> <script nonce="{{g.nonce}}">snow(80);</script>
{% endif %} {% endif %}
{% if p.award_count("frostbite", v) %} {% if p.award_count("frostbite", v) %}
<div class="frost"></div> <div class="frost"></div>
<script> <script nonce="{{g.nonce}}">
const root = document.querySelector(':root'); const root = document.querySelector(':root');
const count = 5; const count = 5;
const opacity = count * 0.1; const opacity = count * 0.1;
root.style.setProperty('--opacity-frost', opacity); root.style.setProperty('--opacity-frost', opacity);
</script> </script>
<style> <style nonce="{{g.nonce}}">
:root { :root {
--opacity-frost: 0.25; --opacity-frost: 0.25;
} }
@ -41,7 +41,7 @@
{% if p.award_count("snowed-in", v) %} {% if p.award_count("snowed-in", v) %}
<canvas id="canvas-snowed-in-overlay"></canvas> <canvas id="canvas-snowed-in-overlay"></canvas>
<canvas id="canvas-snowed-in-lines"></canvas> <canvas id="canvas-snowed-in-lines"></canvas>
<style> <style nonce="{{g.nonce}}">
#canvas-snowed-in-overlay { #canvas-snowed-in-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
@ -64,7 +64,7 @@
</div> </div>
{% if p.award_count("lights", v) %} {% if p.award_count("lights", v) %}
<style> <style nonce="{{g.nonce}}">
#post-root::before { #post-root::before {
content: ""; content: "";
position: absolute; position: absolute;
@ -81,7 +81,7 @@
{% endif %} {% endif %}
{% if p.award_count("candycane", v) %} {% if p.award_count("candycane", v) %}
<style> <style nonce="{{g.nonce}}">
#post-title, #post-content p { #post-title, #post-content p {
--color2: #cc4145; --color2: #cc4145;
--color1: rgb(12, 128, 101); --color1: rgb(12, 128, 101);
@ -108,7 +108,7 @@
{% endif %} {% endif %}
{% if p.award_count("fireplace", v) %} {% if p.award_count("fireplace", v) %}
<style> <style nonce="{{g.nonce}}">
#banner-skybox { #banner-skybox {
fill: url(#skybox-gradient-night) fill: url(#skybox-gradient-night)
} }

View File

@ -1,7 +1,7 @@
{# <script src="{{'event/js/neko.js'|asset}}"></script> #} {# <script src="{{'event/js/neko.js'|asset}}"></script> #}
{% if request.path == '/' %} {% if request.path == '/' %}
<script src="{{'event/js/snow.js'|asset}}"></script> <script src="{{'event/js/snow.js'|asset}}"></script>
<script>snow(80);</script> <script nonce="{{g.nonce}}">snow(80);</script>
{% endif %} {% endif %}
<a rel="nofollow noopener noreferrer" href="https://www.youtube.com/watch?v=BuKft9LpL_0" style="text-decoration: none !important"> <a rel="nofollow noopener noreferrer" href="https://www.youtube.com/watch?v=BuKft9LpL_0" style="text-decoration: none !important">

View File

@ -199,7 +199,7 @@
<circle cx="169.44" cy="10.935"/> <circle cx="169.44" cy="10.935"/>
</g> </g>
<defs> <defs>
<style>.star1 circle {r: 0.5;} <style nonce="{{g.nonce}}">.star1 circle {r: 0.5;}
.star2 circle {r: 0.75;} .star2 circle {r: 0.75;}
.star3 circle {r: 1.0;} .star3 circle {r: 1.0;}
.star4 circle {r: 1.2;} .star4 circle {r: 1.2;}

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -199,7 +199,7 @@
<circle cx="169.44" cy="10.935"/> <circle cx="169.44" cy="10.935"/>
</g> </g>
<defs> <defs>
<style>.star1 circle {r: 0.5;} <style nonce="{{g.nonce}}">.star1 circle {r: 0.5;}
.star2 circle {r: 0.75;} .star2 circle {r: 0.75;}
.star3 circle {r: 1.0;} .star3 circle {r: 1.0;}
.star4 circle {r: 1.2;} .star4 circle {r: 1.2;}

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -3,7 +3,7 @@
{% set path = "assets/event/media/music" %} {% set path = "assets/event/media/music" %}
{% set song = "/" ~ path ~ "/" ~ listdir('files/' ~ path)|random() ~ '?v=45' %} {% set song = "/" ~ path ~ "/" ~ listdir('files/' ~ path)|random() ~ '?v=45' %}
{% endif %} {% endif %}
<script> <script nonce="{{g.nonce}}">
const audio = new Audio("{{song}}"); const audio = new Audio("{{song}}");
audio.loop=true; audio.loop=true;

View File

@ -3,7 +3,7 @@
{% block pagetype %}message{% endblock %} {% block pagetype %}message{% endblock %}
{% block banner %} {% block banner %}
<style> <style nonce="{{g.nonce}}">
.shop-tabs { .shop-tabs {
padding-top: 50px; padding-top: 50px;
} }
@ -59,7 +59,7 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<script> <script nonce="{{g.nonce}}">
function equip_hat(t, hat_id, hat_name) { function equip_hat(t, hat_id, hat_name) {
const profile_pic_hat = document.getElementById("profile-pic-35-hat"); const profile_pic_hat = document.getElementById("profile-pic-35-hat");
function extra_actions(xhr) { function extra_actions(xhr) {

View File

@ -4,7 +4,7 @@
{%- endif -%} {%- endif -%}
<nav class="shadow-md fixed-top"> <nav class="shadow-md fixed-top">
<style> <style nonce="{{g.nonce}}">
body {padding-top: 83px !important} body {padding-top: 83px !important}
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
body { body {
@ -50,7 +50,7 @@
{% endif %} {% endif %}
</div> </div>
{% else %} {% else %}
<style> <style nonce="{{g.nonce}}">
body {padding-top: 54px !important} body {padding-top: 54px !important}
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
body { body {
@ -75,7 +75,7 @@
{% if sub %} {% if sub %}
<a id="sub-name" href="/h/{{sub}}" class="font-weight-bold ml-2 flex-grow-1 mt-1" {% if sub.name|length >= 17 %}style="font-size:max(10px,1.2vw)"{% else %}style="font-size:max(14px,1.2vw)"{% endif %}>{% if not HOLE_STYLE_FLAIR %}/h/{% endif %}{{sub}}</a> <a id="sub-name" href="/h/{{sub}}" class="font-weight-bold ml-2 flex-grow-1 mt-1" {% if sub.name|length >= 17 %}style="font-size:max(10px,1.2vw)"{% else %}style="font-size:max(14px,1.2vw)"{% endif %}>{% if not HOLE_STYLE_FLAIR %}/h/{% endif %}{{sub}}</a>
{% elif has_logo %} {% elif has_logo %}
<style> <style nonce="{{g.nonce}}">
{% if SITE_NAME == 'WPD' %} {% if SITE_NAME == 'WPD' %}
@media (min-width: 1000px) { @media (min-width: 1000px) {
{% else %} {% else %}
@ -358,12 +358,12 @@
<div id="formkey" class="d-none">{{v|formkey}}</div> <div id="formkey" class="d-none">{{v|formkey}}</div>
{% endif %} {% endif %}
<script> <script nonce="{{g.nonce}}">
IMAGE_FORMATS = {{IMAGE_FORMATS|safe}}; IMAGE_FORMATS = {{IMAGE_FORMATS|safe}};
</script> </script>
{% if not v %} {% if not v %}
<style> <style nonce="{{g.nonce}}">
.pad { .pad {
padding-bottom: 7.4px; padding-bottom: 7.4px;
padding-top: 7.4px; padding-top: 7.4px;
@ -372,7 +372,7 @@
{% endif %} {% endif %}
{% if v and v.poor -%} {% if v and v.poor -%}
<style> <style nonce="{{g.nonce}}">
* :not(img[src="/i/hand.webp"] + img, img.golden, img[g], img[glow], .live-circle) { * :not(img[src="/i/hand.webp"] + img, img.golden, img[g], img[glow], .live-circle) {
animation: unset !important; animation: unset !important;
} }

View File

@ -62,7 +62,7 @@
{% block navbar %} {% block navbar %}
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
{% if SITE_NAME != 'WPD' and not sub %} {% if SITE_NAME != 'WPD' and not sub %}
<style> <style nonce="{{g.nonce}}">
@media (max-width: 427px) { @media (max-width: 427px) {
.smol-fp { .smol-fp {
font-size: 2.7vw; font-size: 2.7vw;
@ -169,7 +169,7 @@
{% if request.path == '/' and v %} {% if request.path == '/' and v %}
<script defer src="/assets/js/register_service_worker.js"></script> <script defer src="/assets/js/register_service_worker.js"></script>
<script> <script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
registerServiceWorker( registerServiceWorker(
"/assets/js/service_worker.js", "/assets/js/service_worker.js",
@ -180,7 +180,7 @@
{% endif %} {% endif %}
{% if request.path == '/' and g.browser != 'webview' and time.time() > session.get('tooltip_last_dismissed',0)+86400*30 %} {% if request.path == '/' and g.browser != 'webview' and time.time() > session.get('tooltip_last_dismissed',0)+86400*30 %}
<style> <style nonce="{{g.nonce}}">
.dismiss-beg { .dismiss-beg {
color: #919191; color: #919191;
float: left; float: left;
@ -193,7 +193,7 @@
<div id="mobile-prompt" data-bs-toggle="tooltip" data-bs-container="#mobile-prompt-container" data-bs-placement="top" data-bs-trigger="click" data-bs-html="true" title="<i class='dismiss-beg fas fa-x'></i>Click me to install the {{SITE_NAME}} mobile app!"></div> <div id="mobile-prompt" data-bs-toggle="tooltip" data-bs-container="#mobile-prompt-container" data-bs-placement="top" data-bs-trigger="click" data-bs-html="true" title="<i class='dismiss-beg fas fa-x'></i>Click me to install the {{SITE_NAME}} mobile app!"></div>
</div> </div>
<script> <script nonce="{{g.nonce}}">
if (!window.matchMedia('(display-mode: minimal-ui)')['matches']) { if (!window.matchMedia('(display-mode: minimal-ui)')['matches']) {
if (window.innerWidth <= 737) { if (window.innerWidth <= 737) {
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
@ -214,7 +214,7 @@
} }
</script> </script>
<style> <style nonce="{{g.nonce}}">
#mobile-prompt + .bs-tooltip-bottom { #mobile-prompt + .bs-tooltip-bottom {
transform: None !important; transform: None !important;
inset: 0px 0px auto auto !important; inset: 0px 0px auto auto !important;
@ -224,7 +224,7 @@
{% if request.path == '/' and v and FP %} {% if request.path == '/' and v and FP %}
{% if not v.fp %} {% if not v.fp %}
<script> <script nonce="{{g.nonce}}">
function fp(fp) { function fp(fp) {
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
xhr.open("POST", '/fp/'+fp); xhr.open("POST", '/fp/'+fp);

View File

@ -2,25 +2,25 @@
{% block pagetitle %}Moderation Log{% endblock %} {% block pagetitle %}Moderation Log{% endblock %}
{% block content %} {% block content %}
{% if v %} {% if v %}
<style>:root{--primary:#{{v.themecolor}}}</style> <style nonce="{{g.nonce}}">:root{--primary:#{{v.themecolor}}}</style>
<link rel="stylesheet" href="{{'css/main.css' | asset}}"> <link rel="stylesheet" href="{{'css/main.css' | asset}}">
{% if v.theme == 'classic_dark' %} {% if v.theme == 'classic_dark' %}
<link rel="stylesheet" href="{{('css/classic.css') | asset}}"> <link rel="stylesheet" href="{{('css/classic.css') | asset}}">
{% endif %} {% endif %}
<link rel="stylesheet" href="{{('css/'~v.theme~'.css') | asset}}"> <link rel="stylesheet" href="{{('css/'~v.theme~'.css') | asset}}">
{% if v.agendaposter %} {% if v.agendaposter %}
<style> <style nonce="{{g.nonce}}">
html { html {
cursor:url('/i/dildo.webp?v=2000'), auto; cursor:url('/i/dildo.webp?v=2000'), auto;
} }
</style> </style>
{% elif v.css %} {% elif v.css %}
<style> <style nonce="{{g.nonce}}">
{{v.css | safe}} {{v.css | safe}}
</style> </style>
{% endif %} {% endif %}
{% else %} {% else %}
<style>:root{--primary:#{{DEFAULT_COLOR}}</style> <style nonce="{{g.nonce}}">:root{--primary:#{{DEFAULT_COLOR}}</style>
<link rel="stylesheet" href="{{'css/main.css' | asset}}"> <link rel="stylesheet" href="{{'css/main.css' | asset}}">
<link rel="stylesheet" href="{{('css/'~DEFAULT_THEME~'.css') | asset}}"> <link rel="stylesheet" href="{{('css/'~DEFAULT_THEME~'.css') | asset}}">
{% endif %} {% endif %}

View File

@ -23,7 +23,7 @@
<small><a href="/lost_2fa">Lost your 2FA device?</a></small> <small><a href="/lost_2fa">Lost your 2FA device?</a></small>
<button type="submit" class="btn btn-primary login w-100 mt-3" id="login_button">Sign in</button> <button type="submit" class="btn btn-primary login w-100 mt-3" id="login_button">Sign in</button>
</form> </form>
<script> <script nonce="{{g.nonce}}">
document.getElementById('2fa_token').focus() document.getElementById('2fa_token').focus()
</script> </script>
{% endblock %} {% endblock %}

View File

@ -1,6 +1,6 @@
<div id="form" class="d-none"></div> <div id="form" class="d-none"></div>
<div class="modal fade" id="emojiModal" tabindex="-1" role="dialog"> <div class="modal fade" id="emojiModal" tabindex="-1" role="dialog">
<style> <style nonce="{{g.nonce}}">
#emojiTabs {height: 80%;} #emojiTabs {height: 80%;}
@media (max-width: 650px) { @media (max-width: 650px) {
#emojiTabs {height: 100%;} #emojiTabs {height: 100%;}
@ -70,7 +70,7 @@
I've took the liberty to populate this tab with a selection of Anton's emojis 😽. Next time you'll find the ones you used the most in there 📚 I've took the liberty to populate this tab with a selection of Anton's emojis 😽. Next time you'll find the ones you used the most in there 📚
</div> </div>
<div id="tab-content" class="tab-content d-flex flex-wrap py-3 pl-2" hidden style="text-align:center;"> <div id="tab-content" class="tab-content d-flex flex-wrap py-3 pl-2" hidden style="text-align:center;">
<style> <style nonce="{{g.nonce}}">
.emoji2 { .emoji2 {
/*background: None!important;*/ /*background: None!important;*/
width:60px; width:60px;

View File

@ -152,7 +152,7 @@
</ul> </ul>
</nav> </nav>
{% endif %} {% endif %}
<style> <style nonce="{{g.nonce}}">
.comment { .comment {
margin-top: 0.3rem; margin-top: 0.3rem;
} }

View File

@ -42,7 +42,7 @@
</div> </div>
</div> </div>
<script> <script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
for (const x of ['css','profilecss']) { for (const x of ['css','profilecss']) {
const ta = document.getElementById(`${x}-textarea`); const ta = document.getElementById(`${x}-textarea`);

View File

@ -1,7 +1,7 @@
{% extends "settings.html" %} {% extends "settings.html" %}
{% block pagetitle %}Personal Settings{% endblock %} {% block pagetitle %}Personal Settings{% endblock %}
{% block content %} {% block content %}
<style> <style nonce="{{g.nonce}}">
.bg-image { .bg-image {
padding: 0.25rem; padding: 0.25rem;
width: 15rem; width: 15rem;
@ -279,7 +279,7 @@
{% include "modals/gif.html" %} {% include "modals/gif.html" %}
{% if v.flairchanged %} {% if v.flairchanged %}
<script> <script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
const date = formatDate(new Date({{v.flairchanged}}*1000)); const date = formatDate(new Date({{v.flairchanged}}*1000));
const text = ` - Your flair has been locked until ${date}`; const text = ` - Your flair has been locked until ${date}`;
@ -326,7 +326,7 @@
{{permanent_filter_modal('profanityreplacer', '/settings/personal', 'profanityreplacer', 'Profanity Replacer', 'Soapy-Mouthed Angel')}} {{permanent_filter_modal('profanityreplacer', '/settings/personal', 'profanityreplacer', 'Profanity Replacer', 'Soapy-Mouthed Angel')}}
{%- endif %} {%- endif %}
{% if FEATURES['USERS_PERMANENT_WORD_FILTERS'] -%} {% if FEATURES['USERS_PERMANENT_WORD_FILTERS'] -%}
<script> <script nonce="{{g.nonce}}">
document.addEventListener("DOMContentLoaded", function (event) { document.addEventListener("DOMContentLoaded", function (event) {
const sr_toggle = document.getElementById("slurreplacer"); const sr_toggle = document.getElementById("slurreplacer");
const sr_link = document.getElementById('slurreplacer-perma-link'); const sr_link = document.getElementById('slurreplacer-perma-link');

View File

@ -7,7 +7,7 @@
{% block pagetitle %}Shop{% endblock %} {% block pagetitle %}Shop{% endblock %}
{% block pagetype %}message{% endblock %} {% block pagetype %}message{% endblock %}
{% block banner %} {% block banner %}
<style> <style nonce="{{g.nonce}}">
.shop-tabs { .shop-tabs {
padding-top: 50px; padding-top: 50px;
} }

View File

@ -2,7 +2,7 @@
{% block pagetitle %}/h/{{sub}} Mods{% endblock %} {% block pagetitle %}/h/{{sub}} Mods{% endblock %}
{% block content %} {% block content %}
<script> <script nonce="{{g.nonce}}">
function removeMod(e) { function removeMod(e) {
sendFormXHR(e, sendFormXHR(e,
() => { () => {

View File

@ -8,7 +8,7 @@
{% endblock %} {% endblock %}
{% block pagetype %}thread{% endblock %} {% block pagetype %}thread{% endblock %}
{% block head_final %} {% block head_final %}
<style> <style nonce="{{g.nonce}}">
body > .container { body > .container {
padding-left: 20px !important; padding-left: 20px !important;
padding-right: 20px !important; padding-right: 20px !important;
@ -350,7 +350,7 @@
</div> </div>
{% if offset %} {% if offset %}
<script> <script nonce="{{g.nonce}}">
function viewmore(pid,sort,offset,ids) { function viewmore(pid,sort,offset,ids) {
btn = document.getElementById("viewbtn"); btn = document.getElementById("viewbtn");
btn.disabled = true; btn.disabled = true;
@ -417,7 +417,7 @@
{% if not p.replies %}{% include "comments.html" %}{% endif %} {% if not p.replies %}{% include "comments.html" %}{% endif %}
{% if not v or v.highlightcomments %} {% if not v or v.highlightcomments %}
<script> <script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
showNewCommentCounts('{{p.id}}', {{p.comment_count}}) showNewCommentCounts('{{p.id}}', {{p.comment_count}})
{% if "?context" not in request.full_path %} {% if "?context" not in request.full_path %}
@ -429,10 +429,11 @@
localStorage.setItem("comment-counts", JSON.stringify(comments)) localStorage.setItem("comment-counts", JSON.stringify(comments))
{% endif %} {% endif %}
}) })
</script> </script>
{% endif %} {% endif %}
{% if success %} {% if success %}
<script> <script nonce="{{g.nonce}}">
history.pushState(null, null, '{{p.permalink}}'); history.pushState(null, null, '{{p.permalink}}');
localStorage.setItem("post-title", "") localStorage.setItem("post-title", "")
localStorage.setItem("post-text", "") localStorage.setItem("post-text", "")
@ -448,7 +449,7 @@
{% endif %} {% endif %}
{% if fart and not (v and v.has_badge(128)) %} {% if fart and not (v and v.has_badge(128)) %}
<script> <script nonce="{{g.nonce}}">
fart = Math.floor(Math.random() * 5) + 1 fart = Math.floor(Math.random() * 5) + 1
let audio = new Audio(`/assets/images/${fart}.webp`); let audio = new Audio(`/assets/images/${fart}.webp`);

View File

@ -75,7 +75,7 @@
</div> </div>
{% if offset %} {% if offset %}
<script> <script nonce="{{g.nonce}}">
function viewmore(pid,sort,offset,ids) { function viewmore(pid,sort,offset,ids) {
btn = document.getElementById("viewbtn"); btn = document.getElementById("viewbtn");
btn.disabled = true; btn.disabled = true;

View File

@ -214,7 +214,7 @@
</div> </div>
{% endif %} {% endif %}
<script> <script nonce="{{g.nonce}}">
{% if not v or v.highlightcomments %} {% if not v or v.highlightcomments %}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
showNewCommentCounts({{p.id}}, {{p.comment_count}}) showNewCommentCounts({{p.id}}, {{p.comment_count}})

View File

@ -105,7 +105,7 @@
</div> </div>
{% endblock %} {% endblock %}
{% if request.path == '/submit' %} {% if request.path == '/submit' %}
<script> <script nonce="{{g.nonce}}">
let sub = document.getElementById('sub') let sub = document.getElementById('sub')
if (sub) sub.value = localStorage.getItem("sub") if (sub) sub.value = localStorage.getItem("sub")
</script> </script>

View File

@ -47,7 +47,7 @@
</div> </div>
</div> </div>
<script> <script nonce="{{g.nonce}}">
document.onpaste = function(event) { document.onpaste = function(event) {
files = structuredClone(event.clipboardData.files); files = structuredClone(event.clipboardData.files);

View File

@ -2,7 +2,7 @@
{% block pagetitle %}Submit Marseys{% endblock %} {% block pagetitle %}Submit Marseys{% endblock %}
{% block pagetype %}message{% endblock %} {% block pagetype %}message{% endblock %}
{% block content %} {% block content %}
<style> <style nonce="{{g.nonce}}">
input:not(.btn) { input:not(.btn) {
text-transform: lowercase; text-transform: lowercase;
} }
@ -47,7 +47,7 @@
</div> </div>
</div> </div>
<script> <script nonce="{{g.nonce}}">
document.onpaste = function(event) { document.onpaste = function(event) {
files = structuredClone(event.clipboardData.files); files = structuredClone(event.clipboardData.files);

View File

@ -41,7 +41,7 @@
</div> </div>
</div> </div>
<script> <script nonce="{{g.nonce}}">
document.onpaste = function(event) { document.onpaste = function(event) {
files = structuredClone(event.clipboardData.files); files = structuredClone(event.clipboardData.files);

View File

@ -7,7 +7,7 @@
{% if not HOLIDAY_EVENT %} {% if not HOLIDAY_EVENT %}
<link rel="stylesheet" href="{{('css/transparent.css') | asset}}"> <link rel="stylesheet" href="{{('css/transparent.css') | asset}}">
{% endif %} {% endif %}
<style> <style nonce="{{g.nonce}}">
body { body {
background-image: url('{{u.profile_background}}') !important; background-image: url('{{u.profile_background}}') !important;
} }

View File

@ -10,7 +10,7 @@
<script defer src="{{'js/vendor/bootstrap.js' | asset}}"></script> <script defer src="{{'js/vendor/bootstrap.js' | asset}}"></script>
<script defer src="{{'js/core.js' | asset}}"></script> <script defer src="{{'js/core.js' | asset}}"></script>
<script> <script nonce="{{g.nonce}}">
if (window.matchMedia('(display-mode: minimal-ui)')['matches']) { if (window.matchMedia('(display-mode: minimal-ui)')['matches']) {
const links = document.querySelectorAll('a[data-target="t"]'); const links = document.querySelectorAll('a[data-target="t"]');
for (const link of links) { for (const link of links) {
@ -106,9 +106,9 @@
<link rel="stylesheet" href="{{'css/main.css' | asset}}"> <link rel="stylesheet" href="{{'css/main.css' | asset}}">
<link id="favicon" rel="icon" type="image/webp" href="/icon.webp?v=1"> <link id="favicon" rel="icon" type="image/webp" href="/icon.webp?v=1">
{% if v %} {% if v %}
<style>:root{--primary:#{{v.themecolor}}}</style> <style nonce="{{g.nonce}}">:root{--primary:#{{v.themecolor}}}</style>
{% if v.agendaposter %} {% if v.agendaposter %}
<style> <style nonce="{{g.nonce}}">
html { html {
cursor:url('/i/dildo.webp?v=2000'), auto; cursor:url('/i/dildo.webp?v=2000'), auto;
} }
@ -120,12 +120,12 @@
{% endif %} {% endif %}
<link rel="stylesheet" href="{{('css/'~v.theme~'.css') | asset}}"> <link rel="stylesheet" href="{{('css/'~v.theme~'.css') | asset}}">
{% if v.css and not request.path.startswith('/settings') %} {% if v.css and not request.path.startswith('/settings') %}
<style> <style nonce="{{g.nonce}}">
{{v.css | safe}} {{v.css | safe}}
</style> </style>
{% endif %} {% endif %}
{% if v.themecolor == '30409f' %} {% if v.themecolor == '30409f' %}
<style> <style nonce="{{g.nonce}}">
p a { p a {
color: #2a96f3; color: #2a96f3;
} }
@ -145,7 +145,7 @@
{% endif %} {% endif %}
{% if SITE_NAME == 'rDrama' %} {% if SITE_NAME == 'rDrama' %}
<style> <style nonce="{{g.nonce}}">
.mod:before { .mod:before {
content: '((('; content: '(((';
} }
@ -188,7 +188,7 @@
{% if not HOLIDAY_EVENT %} {% if not HOLIDAY_EVENT %}
<link rel="stylesheet" href="{{('css/transparent.css') | asset}}"> <link rel="stylesheet" href="{{('css/transparent.css') | asset}}">
{% endif %} {% endif %}
<style> <style nonce="{{g.nonce}}">
body { body {
background:url("{{background}}") center center fixed; background:url("{{background}}") center center fixed;
background-color: rgb(var(--background)); background-color: rgb(var(--background));
@ -202,7 +202,7 @@
{% endmacro %} {% endmacro %}
{% macro default_theme() %} {% macro default_theme() %}
<style>:root{--primary:#{{DEFAULT_COLOR}}}</style> <style nonce="{{g.nonce}}">:root{--primary:#{{DEFAULT_COLOR}}}</style>
<link rel="stylesheet" href="{{('css/'~DEFAULT_THEME~'.css') | asset}}"> <link rel="stylesheet" href="{{('css/'~DEFAULT_THEME~'.css') | asset}}">
{% endmacro %} {% endmacro %}

View File

@ -2,4 +2,3 @@ add_header Referrer-Policy "same-origin";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
add_header X-Frame-Options "deny"; add_header X-Frame-Options "deny";
add_header X-Content-Type-Options "nosniff"; add_header X-Content-Type-Options "nosniff";
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' challenges.cloudflare.com rdrama.net; connect-src 'self' tls-use1.fpapi.io api.fpjs.io; object-src 'none';";

View File

@ -1,4 +1,5 @@
include includes/headers; include includes/headers;
add_header Content-Security-Policy "default-src 'none';";
sendfile on; sendfile on;
sendfile_max_chunk 1m; sendfile_max_chunk 1m;
tcp_nopush on; tcp_nopush on;

View File

@ -5,6 +5,7 @@ server {
listen [::]:80; listen [::]:80;
proxy_set_header Host $http_host; proxy_set_header Host $http_host;
include includes/headers; include includes/headers;
add_header Content-Security-Policy "default-src 'none';";
location / { location / {
proxy_pass http://localhost:5000/; proxy_pass http://localhost:5000/;
@ -18,6 +19,7 @@ server {
proxy_set_header Connection "Upgrade"; proxy_set_header Connection "Upgrade";
proxy_pass http://localhost:5001/socket.io; proxy_pass http://localhost:5001/socket.io;
include includes/headers; include includes/headers;
add_header Content-Security-Policy "default-src 'none';";
} }
location /chat { location /chat {
proxy_pass http://localhost:5001/chat; proxy_pass http://localhost:5001/chat;
@ -70,6 +72,16 @@ server {
alias /rDrama/files/assets/images/rDrama/icon.webp; alias /rDrama/files/assets/images/rDrama/icon.webp;
include includes/serve-static; include includes/serve-static;
} }
location =/favicon.ico {
alias /rDrama/files/assets/images/rDrama/icon.webp;
include includes/serve-static;
}
location =/offline.html {
alias /rDrama/files/assets/offline.html;
add_header Content-Security-Policy "default-src 'none'; style-src 'unsafe-inline'; img-src data:;";
}
error_page 502 = /502.html; error_page 502 = /502.html;
location =/502.html { location =/502.html {