Add CSP to local web UI forbidding JavaScript eval()
This commit is contained in:
@@ -198,7 +198,10 @@ def _serve_traversable(
|
||||
return NOT_FOUND
|
||||
content_type = MIMETYPES.get(
|
||||
os.path.splitext(traversable.name)[1].lower(), FALLBACK_MIMETYPE)
|
||||
headers = {"Content-Type": content_type}
|
||||
headers = {
|
||||
"Content-Type": content_type,
|
||||
"Content-Security-Policy": "default-src 'self'; object-src 'none'"
|
||||
}
|
||||
if isinstance(traversable, pathlib.Path):
|
||||
headers["Last-Modified"] = time.strftime(
|
||||
"%a, %d %b %Y %H:%M:%S GMT",
|
||||
|
||||
@@ -112,6 +112,7 @@ main {
|
||||
#logoutview span {
|
||||
width: calc(100% - 60px);
|
||||
display: inline-block;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#logoutview a {
|
||||
@@ -191,6 +192,7 @@ main {
|
||||
font-size: 1em;
|
||||
max-height: 130px;
|
||||
overflow: overlay;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#collectionsscene article:hover ul {
|
||||
@@ -518,3 +520,7 @@ button.inline {
|
||||
margin: 0 2px;
|
||||
width: 1.4em;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -14,17 +14,12 @@
|
||||
<title>Radicale Web Interface</title>
|
||||
<link href="css/main.css" type="text/css" media="screen" rel="stylesheet">
|
||||
<link href="css/icon.png" type="image/png" rel="icon">
|
||||
<style>
|
||||
.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav id="logoutview" class="hidden">
|
||||
<span data-name="user" style="word-wrap:break-word;"></span>
|
||||
<span data-name="user"></span>
|
||||
<a href="#" class="green" data-name="refresh" title="Refresh">Refresh</a>
|
||||
<a href="#" class="red" data-name="logout" title="Logout">Logout</a>
|
||||
</nav>
|
||||
@@ -86,8 +81,8 @@
|
||||
<span data-name="WEBCAL">Webcal</span>
|
||||
</small>
|
||||
<small data-name="contentcount"></small>
|
||||
<input type="text" data-name="url" value="" readonly="" onfocus="this.setSelectionRange(0, 99999);">
|
||||
<p data-name="description" style="word-wrap:break-word;">Description</p>
|
||||
<input type="text" data-name="url" value="" readonly="" class="selectall">
|
||||
<p data-name="description">Description</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="" title="Download" class="green" data-name="download">
|
||||
@@ -162,7 +157,7 @@
|
||||
</td>
|
||||
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span></td>
|
||||
<td><input type="text" data-name="pathortoken" value="" readonly=""
|
||||
onfocus="this.setSelectionRange(0, 99999);" class="inline"></td>
|
||||
class="inline selectall"></td>
|
||||
<td>
|
||||
<button type="button" class="red inline" data-name="delete"><img src="css/icons/delete.svg"
|
||||
class="small_icon" alt="Delete"></button>
|
||||
@@ -187,7 +182,7 @@
|
||||
</td>
|
||||
<td><span class="pill" data-name="rw">rw</span><span class="pill" data-name="ro">ro</span></td>
|
||||
<td><input type="text" data-name="pathortoken" value="" readonly=""
|
||||
onfocus="this.setSelectionRange(0, 99999);" class="inline"></td>
|
||||
class="inline selectall"></td>
|
||||
<td>
|
||||
<button type="button" class="red inline" data-name="delete"><img src="css/icons/delete.svg"
|
||||
class="small_icon" alt="Delete"></button>
|
||||
@@ -225,7 +220,7 @@
|
||||
<tbody data-name="incomingsharesbody">
|
||||
<tr data-name="incomingsharerowtemplate" class="hidden">
|
||||
<td><input type="text" data-name="pathortoken" value="" readonly=""
|
||||
onfocus="this.setSelectionRange(0, 99999);" class="inline"></td>
|
||||
class="inline selectall"></td>
|
||||
<td data-name="owner"></td>
|
||||
<td data-name="permissions"><span class="pill" data-name="rw">rw</span><span class="pill"
|
||||
data-name="ro">ro</span></td>
|
||||
|
||||
@@ -19,12 +19,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { LoginScene } from "./scenes/LoginScene.js";
|
||||
import { LoadingScene } from "./scenes/LoadingScene.js";
|
||||
import { LoginScene } from "./scenes/LoginScene.js";
|
||||
import { push_scene } from "./scenes/scene_manager.js";
|
||||
import { setupSelectAll } from "./utils/misc.js";
|
||||
|
||||
// Add selection handler for input fields with 'selectall' class.
|
||||
setupSelectAll();
|
||||
|
||||
// Hide startup loading message
|
||||
// This works because the LoadingScene is the one that is already active in index.html,
|
||||
// and all other scenes are hidden.
|
||||
new LoadingScene().hide();
|
||||
push_scene(new LoginScene());
|
||||
push_scene(new LoginScene());
|
||||
|
||||
|
||||
@@ -108,3 +108,14 @@ export function bytesToHumanReadable(bytes) {
|
||||
i = Math.min(i, units.length - 1);
|
||||
return Math.round((bytes / Math.pow(1024, i)) * 100) / 100 + ' ' + units[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add selection handler for input fields with 'selectall' class.
|
||||
*/
|
||||
export function setupSelectAll() {
|
||||
document.addEventListener("focusin", (event) => {
|
||||
if (event.target instanceof HTMLInputElement && event.target.classList.contains("selectall")) {
|
||||
event.target.setSelectionRange(0, 99999);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user