Add the HTTP hardening the policy requires before 1.0 (closes #108)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Every answer carries the six security headers REPO_POLICIES.md lists. The Content-Security-Policy allows inline content only with a nonce made for that answer; the pages put it on their style and script blocks and drop their four style attributes. The request log and /ip/ take a forwarded address only from a proxy listed in TRUSTED_PROXIES, which stops the start when set but invalid: the last X-Forwarded-For entry that is not a trusted proxy. X-Real-IP and True-Client-IP are no longer read. The JSON routes and the health check send fixed messages in place of database, parser and resolver errors, and log the detail. Model: opus-5-5
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AS{{.ASN.ASN}} - {{.ASN.Handle}} - RouteWatch</title>
|
||||
<style>
|
||||
<style nonce="{{.CSPNonce}}">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RouteWatch - BGP Route Monitor</title>
|
||||
<style>
|
||||
<style nonce="{{.CSPNonce}}">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -167,6 +167,13 @@
|
||||
color: #95a5a6;
|
||||
margin-top: 8px;
|
||||
}
|
||||
#asname-results p {
|
||||
color: #7f8c8d;
|
||||
margin-top: 12px;
|
||||
}
|
||||
#asname-results .search-message {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* IP Lookup result */
|
||||
.ip-result {
|
||||
@@ -329,7 +336,7 @@
|
||||
<span><a href="{{appGitCommitURL}}">{{appGitRevision}}</a></span>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
<script nonce="{{.CSPNonce}}">
|
||||
function formatNumber(num) {
|
||||
if (num >= 1000000) {
|
||||
return (num / 1000000).toFixed(1) + 'M';
|
||||
@@ -387,7 +394,7 @@
|
||||
if (!query) return;
|
||||
|
||||
const resultsDiv = document.getElementById('asname-results');
|
||||
resultsDiv.innerHTML = '<p class="loading" style="color: #7f8c8d; margin-top: 12px;">Searching...</p>';
|
||||
resultsDiv.innerHTML = '<p class="loading">Searching...</p>';
|
||||
|
||||
// Use a simple client-side search against the asinfo data
|
||||
// For now, redirect to AS page if it looks like an ASN
|
||||
@@ -397,7 +404,7 @@
|
||||
}
|
||||
|
||||
// Show a message that server-side search is coming
|
||||
resultsDiv.innerHTML = '<p style="color: #7f8c8d; margin-top: 12px; font-size: 13px;">AS name search coming soon. For now, try an AS number.</p>';
|
||||
resultsDiv.innerHTML = '<p class="search-message">AS name search coming soon. For now, try an AS number.</p>';
|
||||
});
|
||||
|
||||
// IP lookup
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Prefix}} - RouteWatch</title>
|
||||
<style>
|
||||
<style nonce="{{.CSPNonce}}">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -221,6 +221,10 @@
|
||||
border-radius: 4px;
|
||||
border: 1px solid #e0e0e0;
|
||||
}
|
||||
.origin-item .peer-count {
|
||||
color: #7f8c8d;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
@@ -288,7 +292,7 @@
|
||||
{{else}}
|
||||
No known origin
|
||||
{{end}}
|
||||
<span style="color: #7f8c8d; margin-left: 10px;">{{.PeerCount}} peer{{if ne .PeerCount 1}}s{{end}}</span>
|
||||
<span class="peer-count">{{.PeerCount}} peer{{if ne .PeerCount 1}}s{{end}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Prefixes with /{{ .MaskLength }} - RouteWatch</title>
|
||||
<style>
|
||||
<style nonce="{{.CSPNonce}}">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RouteWatch Status</title>
|
||||
<style>
|
||||
<style nonce="{{.CSPNonce}}">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -130,6 +130,7 @@
|
||||
color: #ef4444;
|
||||
}
|
||||
.error {
|
||||
display: none;
|
||||
background: #fee;
|
||||
color: #c00;
|
||||
padding: 10px;
|
||||
@@ -173,7 +174,7 @@
|
||||
</nav>
|
||||
|
||||
<main class="main-content">
|
||||
<div id="error" class="error" style="display: none;"></div>
|
||||
<div id="error" class="error"></div>
|
||||
<div class="status-grid">
|
||||
<div class="status-card">
|
||||
<h2>RouteWatch</h2>
|
||||
@@ -383,8 +384,8 @@
|
||||
<div id="handler-stats-container" class="status-grid">
|
||||
<!-- Handler stats will be dynamically added here -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
<script nonce="{{.CSPNonce}}">
|
||||
function formatBytes(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
const k = 1024;
|
||||
|
||||
Reference in New Issue
Block a user