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';
const CACHE_NAME = "offlineCache-v1";
const OFFLINE_URL = "/assets/offline.html";
const OFFLINE_URL = "/offline.html";
self.addEventListener("install", () => {
const cacheOfflinePage = async () => {

View File

@ -13,26 +13,30 @@ def session_init():
@app.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:
abort(403, "Unauthorized host provided!")
if SITE == 'marsey.world' and request.path != '/kofi':
abort(404)
if request.headers.get("CF-Worker"):
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:
g.browser = 'webview'
@ -54,11 +58,57 @@ def before_request():
limiter.check()
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
def after_request(response:Response):
if response.status_code < 400:
_set_cloudflare_cookie(response)
_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

View File

@ -333,3 +333,11 @@ if not os.path.exists(f'files/templates/donate_{SITE_NAME}.html'):
@auth_desired_with_logingate
def donate(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 secrets
from flask import g, request, session
from files.classes.clients import ClientAuth
@ -40,7 +41,8 @@ def get_logged_in_user():
else:
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']):
abort(403)
@ -67,6 +69,10 @@ def get_logged_in_user():
if f'@{v.username}, ' not in f.read():
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')
if not g.is_api:
g.nonce = secrets.token_urlsafe(16)
return v
def auth_desired(f):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,8 +3,6 @@
<html>
<head>
<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="x-apple-disable-message-reformatting">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

View File

@ -3,35 +3,8 @@
<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 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/midnight.css?v=4000">
@ -50,7 +23,6 @@
<meta name="viewport" content="width=device-width,initial-scale=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="shortcut icon" href="/icon.webp?v=1">
<meta name="apple-mobile-web-app-title" content="WPD">
@ -93,7 +65,7 @@
<nav class="shadow-md fixed-top">
<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">
<img id="header--icon" alt="header icon" src="/i/WPD/headericon.webp?v=3009">
</a>
@ -105,10 +77,10 @@
</div>
<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="">
<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>
</span>
</span>

View File

@ -3,35 +3,8 @@
<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 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/midnight.css?v=4000">
@ -50,7 +23,6 @@
<meta name="viewport" content="width=device-width,initial-scale=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="shortcut icon" href="/icon.webp?v=1">
<meta name="apple-mobile-web-app-title" content="rDrama">
@ -93,7 +65,7 @@
<nav class="shadow-md fixed-top">
<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">
<img id="header--icon" alt="header icon" src="/i/rDrama/headericon.webp?v=3009">
</a>
@ -105,10 +77,10 @@
</div>
<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="">
<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>
</span>
</span>

View File

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

View File

@ -1,7 +1,7 @@
{# <script src="{{'event/js/neko.js'|asset}}"></script> #}
{% if request.path == '/' %}
<script src="{{'event/js/snow.js'|asset}}"></script>
<script>snow(80);</script>
<script nonce="{{g.nonce}}">snow(80);</script>
{% endif %}
<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"/>
</g>
<defs>
<style>.star1 circle {r: 0.5;}
<style nonce="{{g.nonce}}">.star1 circle {r: 0.5;}
.star2 circle {r: 0.75;}
.star3 circle {r: 1.0;}
.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"/>
</g>
<defs>
<style>.star1 circle {r: 0.5;}
<style nonce="{{g.nonce}}">.star1 circle {r: 0.5;}
.star2 circle {r: 0.75;}
.star3 circle {r: 1.0;}
.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 song = "/" ~ path ~ "/" ~ listdir('files/' ~ path)|random() ~ '?v=45' %}
{% endif %}
<script>
<script nonce="{{g.nonce}}">
const audio = new Audio("{{song}}");
audio.loop=true;

View File

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

View File

@ -4,7 +4,7 @@
{%- endif -%}
<nav class="shadow-md fixed-top">
<style>
<style nonce="{{g.nonce}}">
body {padding-top: 83px !important}
@media (max-width: 767.98px) {
body {
@ -50,7 +50,7 @@
{% endif %}
</div>
{% else %}
<style>
<style nonce="{{g.nonce}}">
body {padding-top: 54px !important}
@media (max-width: 767.98px) {
body {
@ -75,7 +75,7 @@
{% 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>
{% elif has_logo %}
<style>
<style nonce="{{g.nonce}}">
{% if SITE_NAME == 'WPD' %}
@media (min-width: 1000px) {
{% else %}
@ -358,12 +358,12 @@
<div id="formkey" class="d-none">{{v|formkey}}</div>
{% endif %}
<script>
<script nonce="{{g.nonce}}">
IMAGE_FORMATS = {{IMAGE_FORMATS|safe}};
</script>
{% if not v %}
<style>
<style nonce="{{g.nonce}}">
.pad {
padding-bottom: 7.4px;
padding-top: 7.4px;
@ -372,7 +372,7 @@
{% endif %}
{% 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) {
animation: unset !important;
}

View File

@ -62,7 +62,7 @@
{% block navbar %}
<div class="d-flex align-items-center">
{% if SITE_NAME != 'WPD' and not sub %}
<style>
<style nonce="{{g.nonce}}">
@media (max-width: 427px) {
.smol-fp {
font-size: 2.7vw;
@ -169,7 +169,7 @@
{% if request.path == '/' and v %}
<script defer src="/assets/js/register_service_worker.js"></script>
<script>
<script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function () {
registerServiceWorker(
"/assets/js/service_worker.js",
@ -180,7 +180,7 @@
{% endif %}
{% 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 {
color: #919191;
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>
<script>
<script nonce="{{g.nonce}}">
if (!window.matchMedia('(display-mode: minimal-ui)')['matches']) {
if (window.innerWidth <= 737) {
document.addEventListener('DOMContentLoaded', function() {
@ -214,7 +214,7 @@
}
</script>
<style>
<style nonce="{{g.nonce}}">
#mobile-prompt + .bs-tooltip-bottom {
transform: None !important;
inset: 0px 0px auto auto !important;
@ -224,7 +224,7 @@
{% if request.path == '/' and v and FP %}
{% if not v.fp %}
<script>
<script nonce="{{g.nonce}}">
function fp(fp) {
const xhr = new XMLHttpRequest();
xhr.open("POST", '/fp/'+fp);

View File

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

View File

@ -23,7 +23,7 @@
<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>
</form>
<script>
<script nonce="{{g.nonce}}">
document.getElementById('2fa_token').focus()
</script>
{% endblock %}

View File

@ -1,6 +1,6 @@
<div id="form" class="d-none"></div>
<div class="modal fade" id="emojiModal" tabindex="-1" role="dialog">
<style>
<style nonce="{{g.nonce}}">
#emojiTabs {height: 80%;}
@media (max-width: 650px) {
#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 📚
</div>
<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 {
/*background: None!important;*/
width:60px;

View File

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

View File

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

View File

@ -1,7 +1,7 @@
{% extends "settings.html" %}
{% block pagetitle %}Personal Settings{% endblock %}
{% block content %}
<style>
<style nonce="{{g.nonce}}">
.bg-image {
padding: 0.25rem;
width: 15rem;
@ -279,7 +279,7 @@
{% include "modals/gif.html" %}
{% if v.flairchanged %}
<script>
<script nonce="{{g.nonce}}">
document.addEventListener('DOMContentLoaded', function() {
const date = formatDate(new Date({{v.flairchanged}}*1000));
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')}}
{%- endif %}
{% if FEATURES['USERS_PERMANENT_WORD_FILTERS'] -%}
<script>
<script nonce="{{g.nonce}}">
document.addEventListener("DOMContentLoaded", function (event) {
const sr_toggle = document.getElementById("slurreplacer");
const sr_link = document.getElementById('slurreplacer-perma-link');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,6 +5,7 @@ server {
listen [::]:80;
proxy_set_header Host $http_host;
include includes/headers;
add_header Content-Security-Policy "default-src 'none';";
location / {
proxy_pass http://localhost:5000/;
@ -18,6 +19,7 @@ server {
proxy_set_header Connection "Upgrade";
proxy_pass http://localhost:5001/socket.io;
include includes/headers;
add_header Content-Security-Policy "default-src 'none';";
}
location /chat {
proxy_pass http://localhost:5001/chat;
@ -70,6 +72,16 @@ server {
alias /rDrama/files/assets/images/rDrama/icon.webp;
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;
location =/502.html {