aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOsmium Sorcerer <os@sof.beauty>2026-06-06 02:27:32 +0000
committerOsmium Sorcerer <os@sof.beauty>2026-06-06 03:09:27 +0000
commit8bf3cae6ac89de9569a7ec629594954804a2b55a (patch)
treed897073049c414e15dd33c0ad1dac4345801b22e
parente0ce108e0806d18353ad85125b2b5f1b1c67e07d (diff)
CSP hardening: remove inline styles
Similar to removal of inline scripts, everything was taken out into the CSS files, with the same styles applied there directly. This lets us use `script-src 'self'` in the CSP. Additionally, serve Golden Layout CSS locally to avoid third-party connection.
-rw-r--r--public/client.html111
-rw-r--r--public/index.html2
-rw-r--r--webAO/dom/toggleElement.js6
-rw-r--r--webAO/golden/css/goldenlayout-dark-theme.css1
-rw-r--r--webAO/packets/handlers/handleFL.ts14
-rw-r--r--webAO/packets/handlers/handlePV.ts5
-rw-r--r--webAO/styles/client.css131
-rw-r--r--webAO/styles/master.css4
8 files changed, 184 insertions, 90 deletions
diff --git a/public/client.html b/public/client.html
index 55214d30..1cb2b1f7 100644
--- a/public/client.html
+++ b/public/client.html
@@ -82,24 +82,15 @@
<link
type="text/css"
rel="stylesheet"
- href="https://golden-layout.com/files/latest/css/goldenlayout-dark-theme.css"
+ href="golden/css/goldenlayout-dark-theme.css"
/>
- <style>
- #client_ooclog {
- text-align: left;
- }
-
- #client_ooclog a {
- color: white;
- }
- </style>
<script src="lib/jdataview.min.js" async defer></script>
</head>
<body>
<div id="client_waiting">
<noscript>
- <p style="color: red">webAO requires JavaScript to work</p>
+ <p class="error">webAO requires JavaScript to work</p>
</noscript>
<div id="client_loading">
<h1 id="client_loadingtext">Loading</h1>
@@ -116,7 +107,7 @@
<div id="client_chartable"></div>
</div>
</div>
- <div id="client_error_overlay" style="display: none">
+ <div id="client_error_overlay">
<div id="client_error">
<div id="client_error_icon">&#x26A0;</div>
<h2 id="client_errortext"></h2>
@@ -214,7 +205,7 @@
alt="Shout overlay"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII="
/>
- <div id="client_chatcontainer" style="font-size: 12px; opacity: 0">
+ <div id="client_chatcontainer">
<div id="client_chatdecoration"></div>
<div id="client_name">
<p id="client_inner_name"></p>
@@ -290,8 +281,7 @@
<button
id="button_4"
alt="Custom"
- class="client_button"
- style="display: none"
+ class="client_button nodisplay"
data-action="toggle-shout"
data-id="4"
>
@@ -327,8 +317,7 @@
<button
id="button_flip"
alt="Flip"
- class="client_button"
- style="display: none"
+ class="client_button nodisplay"
data-action="toggle-effect"
>
Flip
@@ -344,8 +333,7 @@
<button
id="button_shake"
alt="Shake"
- class="client_button"
- style="display: none"
+ class="client_button nodisplay"
data-action="toggle-effect"
>
Shake
@@ -387,22 +375,20 @@
</button>
<br />
<br />
- <span id="pairing" style="display: none">
+ <span id="pairing">
<button
id="button_toggle_pairing"
alt="Pairing"
- class="client_button"
+ class="client_button nodisplay"
>
Pairing
</button>
- <span id="pairing_settings" style="display: none">
+ <span id="pairing_settings" class="nodislpay">
<label for="pair_select">Pairing partner:</label>
<select name="pair_select" id="pair_select">
<option value="-1">None</option>
</select>
- <table
- style="border: none; margin-left: auto; margin-right: auto"
- >
+ <table id="pairing_table">
<tr>
<td>
<p>Horizontal offset:</p>
@@ -418,7 +404,7 @@
/>
</td>
</tr>
- <tr id="y_offset" style="display: none">
+ <tr id="y_offset" class="nodisplay">
<td>
<p>Vertical offset:</p>
</td>
@@ -443,7 +429,7 @@
</span>
<br />
<br />
- <span id="cccc" style="display: none">
+ <span id="cccc" class="nodisplay">
<label for="ic_chat_name">Custom Showname:</label>
<input id="ic_chat_name" name="ic_chat_name" type="text" />
<br />
@@ -461,13 +447,13 @@
</span>
<br />
<br />
- <span id="2.7" style="display: none">
+ <span id="2.7" class="nodisplay">
<label for="check_loopsfx">Looping SFX:</label>
<input type="checkbox" name="check_loopsfx" id="check_loopsfx" />
</span>
<br />
<br />
- <span id="2.8" style="display: none">
+ <span id="2.8" class="nodisplay">
<label for="check_additive">Additive:</label>
<input type="checkbox" name="check_additive" id="check_additive" />
<br />
@@ -484,63 +470,49 @@
</span>
</div>
</div>
- <fieldset style="margin: 10px">
+ <fieldset id="judge_fieldset">
<legend>Actions</legend>
<!-- Judge Commands -->
- <span id="judge_action" style="display: none">
+ <span id="judge_action" class="nodisplay">
<span
id="menu_wt"
class="judge_button"
- style="color: blue"
><i>Witness<br />Testimony</i></span
>
<span
id="menu_ce"
class="judge_button"
- style="color: red"
><i>Cross<br />Examination</i></span
>
<span
id="menu_nguilty"
class="judge_button"
- style="
- color: white;
- font-family: serif;
- text-shadow:
- -1px 0 #000,
- 0 1px #000,
- 1px 0 #000,
- 0 -1px #000;
- font-size: 1.5em;
- line-height: 0.75;
- "
>Not<br />Guilty</span
>
<span
id="menu_guilty"
class="judge_button"
- style="color: black; font-family: serif; font-size: 1.5em"
>Guilty</span
>
<br />
- <span style="display: inline-block; vertical-align: middle">
+ <span class="menu-hp-bar">
<span id="menu_rhpd" class="healthchange_button">
&#8863;
</span>
- <span style="font-size: 1.25em">Defense</span>
+ <span class="menu-hp-label">Defense</span>
<span id="menu_ahpd" class="healthchange_button">
&#8862;
</span>
</span>
- <span style="display: inline-block; vertical-align: middle">
+ <span class="menu-hp-bar">
<span id="menu_ahpp" class="healthchange_button">
&#8862;
</span>
- <span style="font-size: 1.25em">Prosecution</span>
+ <span class="menu-hp-label">Prosecution</span>
<span id="menu_rhpp" class="healthchange_button">
&#8863;
</span>
@@ -551,7 +523,7 @@
<br />
<br />
<span id="muting">
- <label for="mute_select" style="float: left"
+ <label for="mute_select" id="mute_label"
>Mute a character:
</label>
<select
@@ -586,7 +558,7 @@
</span>
<span id="menu_cm" class="menu_button">
<b class="menu_icon">&#128680;</b>
- <div class="menu_text" style="color: #ce2727">Call Mod</div>
+ <div id="callmod_button" class="menu_text">Call Mod</div>
</span>
</div>
<div class="hrtext">
@@ -597,7 +569,7 @@
<meta name="frame-title" lang="en" content="Areas" />
<div id="areas"></div>
<br />
- <fieldset style="text-align: left">
+ <fieldset class="l-fieldset">
<legend>Current Area Background</legend>
<span>
<img
@@ -607,20 +579,20 @@
data-error="img"
/>
</span>
- <span style="display: inline-block">
+ <span id="bg_span">
<label for="bg_filename">Background:</label>
<br />
<select
id="bg_select"
name="bg_select"
- style="margin-top: 10px"
+ class="bg-selection"
></select>
<br />
<input
id="bg_filename"
name="bg_filename"
type="text"
- style="margin-top: 10px"
+ class="bg-selection"
/>
<br />
<br />
@@ -633,7 +605,7 @@
</button>
</span>
</fieldset>
- <fieldset style="text-align: left; display: none">
+ <fieldset class="l-fieldset nodisplay">
<legend>Timers</legend>
<span id="client_timer0">00:00:00</span>
<span id="client_timer1">00:00:00</span>
@@ -662,12 +634,10 @@
<!-- Evidence section -->
<span class="menu_content" id="content_2">
<meta name="frame-title" lang="en" content="Evidence" />
- <fieldset
- style="text-align: left; display: flex; flex-direction: column"
- >
+ <fieldset id="evi_fieldset">
<legend>Information</legend>
<hr />
- <div style="display: flex">
+ <div id="evi_info">
<img
id="evi_preview"
class="evi_icon"
@@ -697,7 +667,7 @@
</div>
</div>
<hr />
- <div style="display: flex; padding-top: 5px">
+ <div id="evi_desc_container">
<textarea
id="evi_desc"
name="evi_desc"
@@ -706,7 +676,7 @@
placeholder="Evidence description"
></textarea>
</div>
- <div style="display: block; text-align: center; padding-top: 20px">
+ <div id="evi_add_container">
<button
id="evi_add"
alt="Add Evidence"
@@ -905,7 +875,7 @@
</span>
<br />
<br />
- <fieldset style="margin: 1rem auto; padding: 1rem; max-width: 200px;">
+ <fieldset id="auth_fieldset">
<legend>Authenticate</legend>
<div><button type="button" id="use_passkey" class="client_button hover_button">Use passkey</button></div>
</fieldset>
@@ -920,7 +890,7 @@
<span class="menu_content" id="content_4">
<meta name="frame-title" lang="en" content="About" />
<img id="about-logo" src="logo-new.png" alt="Attorney Online logo" />
- <h1 style="line-height: 0.3em">webAO</h1>
+ <h1 id="webao_title">webAO</h1>
<h3 id="client_version">version</h3>
<p>
Client created by
@@ -953,11 +923,8 @@
<template id="ooc">
<meta name="frame-title" lang="en" content="Server" />
- <div
- id="client_ooc"
- style="height: 100%; display: flex; flex-direction: column"
- >
- <div id="client_ooclog" style="flex: 1 auto" readonly></div>
+ <div id="client_ooc">
+ <div id="client_ooclog" readonly></div>
<span id="client_oocinput">
<input id="OOC_name" name="OOC_name" type="text" />
<input
@@ -967,17 +934,17 @@
</span>
<span
id="client_replaycontrols"
- style="display: none; white-space: nowrap"
+ class="nodisplay"
>
<input
id="client_replaygo"
- style="width: 25%"
+ class="replay-control"
type="button"
value="GO"
/>
<input
id="client_replaytimer"
- style="width: 25%"
+ class="replay-control"
type="number"
value="2000"
/>
diff --git a/public/index.html b/public/index.html
index 7970295d..8558d2ba 100644
--- a/public/index.html
+++ b/public/index.html
@@ -107,7 +107,7 @@
</nav>
<form id="serverlist_container" class="monocle-enriched">
<h2>Server List</h2>
- <div id="ms_error" class="error" style="display: none">
+ <div id="ms_error" class="error">
<p>Could not connect to the master server.</p>
<p>Showing saved list.</p>
</div>
diff --git a/webAO/dom/toggleElement.js b/webAO/dom/toggleElement.js
index 76a1c633..c87561d0 100644
--- a/webAO/dom/toggleElement.js
+++ b/webAO/dom/toggleElement.js
@@ -4,10 +4,10 @@
*/
export function toggleElement(elementId) {
const element = document.getElementById(elementId);
- if (element.style.display !== "none") {
- element.style.display = "none";
+ if ("nodisplay" in element.classList) {
+ element.classList.remove("nodisplay");
} else {
- element.style.display = "block";
+ element.classList.add("nodisplay");
}
}
window.toggleElement = toggleElement;
diff --git a/webAO/golden/css/goldenlayout-dark-theme.css b/webAO/golden/css/goldenlayout-dark-theme.css
new file mode 100644
index 00000000..beb8e3b0
--- /dev/null
+++ b/webAO/golden/css/goldenlayout-dark-theme.css
@@ -0,0 +1 @@
+.lm_goldenlayout{background:#000000}.lm_content{background:#222222}.lm_dragProxy .lm_content{box-shadow:2px 2px 4px rgba(0,0,0,0.9)}.lm_dropTargetIndicator{box-shadow:inset 0 0 30px #000000;outline:1px dashed #cccccc;transition:all 200ms ease}.lm_dropTargetIndicator .lm_inner{background:#000000;opacity:.2}.lm_splitter{background:#000000;opacity:.001;transition:opacity 200ms ease}.lm_splitter:hover,.lm_splitter.lm_dragging{background:#444444;opacity:1}.lm_header{height:20px;user-select:none}.lm_header.lm_selectable{cursor:pointer}.lm_header .lm_tab{font-family:Arial,sans-serif;font-size:12px;color:#999999;background:#111111;box-shadow:2px -2px 2px rgba(0,0,0,0.3);margin-right:2px;padding-bottom:2px;padding-top:2px}.lm_header .lm_tab .lm_close_tab{width:11px;height:11px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAATElEQVR4nG3OwQ0DMQwDwZGRBtR/j1YJzMc5+IDoR+yCVO29g+pu981MFgqZmRdAfU7+CYWcbF11LwALjpBL0N0qybNx/RPU+gOeiS/+XCRwDlTgkQAAAABJRU5ErkJggg==);background-position:center center;background-repeat:no-repeat;top:4px;right:6px;opacity:.4}.lm_header .lm_tab .lm_close_tab:hover{opacity:1}.lm_header .lm_tab.lm_active{border-bottom:none;box-shadow:0 -2px 2px #000000;padding-bottom:3px}.lm_header .lm_tab.lm_active .lm_close_tab{opacity:1}.lm_dragProxy.lm_bottom .lm_header .lm_tab,.lm_stack.lm_bottom .lm_header .lm_tab{box-shadow:2px 2px 2px rgba(0,0,0,0.3)}.lm_dragProxy.lm_bottom .lm_header .lm_tab.lm_active,.lm_stack.lm_bottom .lm_header .lm_tab.lm_active{box-shadow:0 2px 2px #000000}.lm_selected .lm_header{background-color:#452500}.lm_tab:hover,.lm_tab.lm_active{background:#222222;color:#dddddd}.lm_header .lm_controls .lm_tabdropdown:before{color:#ffffff}.lm_controls>li{position:relative;background-position:center center;background-repeat:no-repeat;opacity:.4;transition:opacity 300ms ease}.lm_controls>li:hover{opacity:1}.lm_controls .lm_popout{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAPklEQVR4nI2Q0QoAIAwCNfr/X7aXCpGN8snBdgejJOzckpkxs9jR6K6T5JpU0nWl5pSXTk7qwh8SnNT+CAAWCgkKFpuSWsUAAAAASUVORK5CYII=)}.lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAKElEQVR4nGP8////fwYCgImQAgYGBgYWKM2IR81/okwajIpgvsMbVgAwgQYRVakEKQAAAABJRU5ErkJggg==)}.lm_controls .lm_close{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAQUlEQVR4nHXOQQ4AMAgCQeT/f6aXpsGK3jSTuCVJAAr7iBdoAwCKd0nwfaAdHbYERw5b44+E8JoBjEYGMBq5gAYP3usUDu2IvoUAAAAASUVORK5CYII=)}.lm_maximised .lm_header{background-color:#000000}.lm_maximised .lm_controls .lm_maximise{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAJ0lEQVR4nGP8//8/AzGAiShVI1YhCwMDA8OsWbPwBmZaWhoj0SYCAN1lBxMAX4n0AAAAAElFTkSuQmCC)}.lm_transition_indicator{background-color:#000000;border:1px dashed #555555}.lm_popin{cursor:pointer}.lm_popin .lm_bg{background:#ffffff;opacity:.3}.lm_popin .lm_icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA0AAAAJCAYAAADpeqZqAAAAWklEQVR4nJWOyw3AIAxDHcQC7L8jbwT3AlJBfNp3SiI7dtRaLSlKKeoA1oEsKSQZCEluexw8Tm3ohk+E7bnOUHUGcNh+HwbBygw4AZ7FN/Lt84p0l+yTflV8AKQyLdcCRJi/AAAAAElFTkSuQmCC);background-position:center center;background-repeat:no-repeat;border-left:1px solid #eeeeee;border-top:1px solid #eeeeee;opacity:.7}.lm_popin:hover .lm_icon{opacity:1}/*# sourceMappingURL=goldenlayout-dark-theme.css.map */ \ No newline at end of file
diff --git a/webAO/packets/handlers/handleFL.ts b/webAO/packets/handlers/handleFL.ts
index 5479f4ef..b9647f14 100644
--- a/webAO/packets/handlers/handleFL.ts
+++ b/webAO/packets/handlers/handleFL.ts
@@ -19,24 +19,24 @@ export const handleFL = (args: string[]) => {
}
if (args.includes("cccc_ic_support")) {
- document.getElementById("cccc")!.style.display = "";
- document.getElementById("pairing")!.style.display = "";
+ document.getElementById("cccc")!.classList.remove("nodisplay");
+ document.getElementById("pairing")!.classList.remove("nodisplay");
}
if (args.includes("flipping")) {
- document.getElementById("button_flip")!.style.display = "";
+ document.getElementById("button_flip")!.classList.remove("nodisplay");
}
if (args.includes("looping_sfx")) {
- document.getElementById("button_shake")!.style.display = "";
- document.getElementById("2.7")!.style.display = "";
+ document.getElementById("button_shake")!.classList.remove("nodisplay");
+ document.getElementById("2.7")!.classList.remove("nodisplay");
}
if (args.includes("effects")) {
- document.getElementById("2.8")!.style.display = "";
+ document.getElementById("2.8")!.classList.remove("nodisplay");
}
if (args.includes("y_offset")) {
- document.getElementById("y_offset")!.style.display = "";
+ document.getElementById("y_offset")!.classList.remove("nodisplay");
}
};
diff --git a/webAO/packets/handlers/handlePV.ts b/webAO/packets/handlers/handlePV.ts
index 2e14ad2f..28eaf741 100644
--- a/webAO/packets/handlers/handlePV.ts
+++ b/webAO/packets/handlers/handlePV.ts
@@ -99,9 +99,6 @@ export const handlePV = async (args: string[]) => {
`${AO_HOST}characters/${encodeURI(me.name)}/custom.gif`,
)
) {
- document.getElementById("button_4")!.style.display = "";
- } else {
- document.getElementById("button_4")!.style.display = "none";
+ document.getElementById("button_4")!.classList.remove("nodisplay");
}
-
};
diff --git a/webAO/styles/client.css b/webAO/styles/client.css
index fa01ddc6..8dfd5daa 100644
--- a/webAO/styles/client.css
+++ b/webAO/styles/client.css
@@ -65,7 +65,7 @@
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
- display: flex;
+ display: none;
justify-content: center;
align-items: center;
z-index: 200;
@@ -95,6 +95,7 @@
#client_errortext {
margin: 4px 0 8px;
text-align: center;
+ white-space: pre-wrap;
}
#client_error_code {
@@ -594,12 +595,17 @@
font-size: small;
overflow-wrap: break-word;
overflow-y: auto;
+ text-align: left;
text-rendering: optimizelegibility;
resize: none;
flex: 1 1 auto;
border: none;
}
+#client_ooclog a {
+ color: white;
+}
+
#client_oocinput {
display: flex;
flex-flow: row nowrap;
@@ -814,6 +820,125 @@
white-space: pre-wrap;
}
-#client_errortext {
- white-space: pre-wrap;
+.error {
+ color: red;
+}
+
+#client_chatcontainer {
+ font-size: 12px;
+ opacity: 0;
+}
+
+.nodisplay {
+ display: none;
+}
+
+#pairing_table {
+ border: none;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#judge_fieldset {
+ margin: 10px;
+}
+
+#menu_wt {
+ color: blue;
+}
+
+#menu_ce {
+ color: red;
+}
+
+#menu_nguilty {
+ color: white;
+ font-family: serif;
+ text-shadow:
+ -1px 0 #000,
+ 0 1px #000,
+ 1px 0 #000,
+ 0 -1px #000;
+ font-size: 1.5em;
+ line-height: 0.75;
+}
+
+#menu_guilty {
+ color: black;
+ font-family: serif;
+ font-size: 1.5em;
+}
+
+.menu-hp-bar {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+.menu-hp-label {
+ font-size: 1.25em;
+}
+
+#mute_label {
+ float: left;
+}
+
+#callmod_button {
+ color: #ce2727;
+}
+
+.l-fieldset {
+ text-align: left;
+}
+
+#bg_span {
+ display: inline-block;
+}
+
+.bg-selection {
+ margin-top: 10px;
+}
+
+#evi_fieldset {
+ text-align: left;
+ display: flex;
+ flex-direction: column;
+}
+
+#evi_info {
+ display: flex;
+}
+
+#evi_desc_container {
+ display: flex;
+ padding-top: 5px;
+}
+
+#evi_add_container {
+ display: block;
+ text-align: center;
+ padding-top: 20px;
+}
+
+#auth_fieldset {
+ margin: 1rem auto;
+ padding: 1rem;
+ max-width: 200px;
+}
+
+#webao_title {
+ line-height: 0.3em;
+}
+
+#client_ooc {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+#client_replaycontrols {
+ white-space: nowrap;
+}
+
+.replay-control {
+ width: 25%;
}
diff --git a/webAO/styles/master.css b/webAO/styles/master.css
index add9ed21..c5d9b197 100644
--- a/webAO/styles/master.css
+++ b/webAO/styles/master.css
@@ -379,3 +379,7 @@ nav.navbar.fixed-top.navbar-expand-lg.navbar-dark.bg-dark.fixed-top {
.server-description {
white-space: pre-wrap;
}
+
+#ms_error {
+ display: none;
+}