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