diff options
| author | Osmium Sorcerer <os@sof.beauty> | 2026-06-06 02:27:32 +0000 |
|---|---|---|
| committer | Osmium Sorcerer <os@sof.beauty> | 2026-06-06 03:09:27 +0000 |
| commit | 8bf3cae6ac89de9569a7ec629594954804a2b55a (patch) | |
| tree | d897073049c414e15dd33c0ad1dac4345801b22e | |
| parent | e0ce108e0806d18353ad85125b2b5f1b1c67e07d (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.html | 111 | ||||
| -rw-r--r-- | public/index.html | 2 | ||||
| -rw-r--r-- | webAO/dom/toggleElement.js | 6 | ||||
| -rw-r--r-- | webAO/golden/css/goldenlayout-dark-theme.css | 1 | ||||
| -rw-r--r-- | webAO/packets/handlers/handleFL.ts | 14 | ||||
| -rw-r--r-- | webAO/packets/handlers/handlePV.ts | 5 | ||||
| -rw-r--r-- | webAO/styles/client.css | 131 | ||||
| -rw-r--r-- | webAO/styles/master.css | 4 |
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">⚠</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"> ⊟ </span> - <span style="font-size: 1.25em">Defense</span> + <span class="menu-hp-label">Defense</span> <span id="menu_ahpd" class="healthchange_button"> ⊞ </span> </span> - <span style="display: inline-block; vertical-align: middle"> + <span class="menu-hp-bar"> <span id="menu_ahpp" class="healthchange_button"> ⊞ </span> - <span style="font-size: 1.25em">Prosecution</span> + <span class="menu-hp-label">Prosecution</span> <span id="menu_rhpp" class="healthchange_button"> ⊟ </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">🚨</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; +} |
