Show the IP information API on the home page (closes #156)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
The home page gets an IP information API card. It shows the curl command that asks /ip/ about the visitor's own address. The page then makes that same request and shows the JSON answer, pretty-printed. An error answer, such as a 404 for an address with no route, is shown the same way. A request that fails shows an error line. The server gives the page the visitor's address, found as /ip/ finds it, so a trusted proxy's X-Forwarded-For is honoured. The command takes its origin from the browser, so it names the host the visitor used. Model: opus-5-5
This commit is contained in:
@@ -239,7 +239,8 @@
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
.ip-result pre {
|
||||
.ip-result pre,
|
||||
#ip-api pre {
|
||||
background: #2c3e50;
|
||||
color: #ecf0f1;
|
||||
padding: 16px;
|
||||
@@ -251,18 +252,30 @@
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.ip-result .error {
|
||||
.ip-result .error,
|
||||
#ip-api .error {
|
||||
background: #fee;
|
||||
color: #c00;
|
||||
padding: 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.ip-result .loading {
|
||||
.ip-result .loading,
|
||||
#ip-api .loading {
|
||||
color: #7f8c8d;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* IP information API card: the command, then its answer */
|
||||
#ip-api p {
|
||||
margin: 0;
|
||||
color: #7f8c8d;
|
||||
font-size: 14px;
|
||||
}
|
||||
#ip-api pre {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
margin-top: 40px;
|
||||
@@ -367,6 +380,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="search-card" id="ip-api">
|
||||
<h2>IP Information API</h2>
|
||||
<p>The API answers what RouteWatch knows about an IP address, such as its AS number and country. <code>/ip/</code> with no address answers for the caller's own address.</p>
|
||||
<pre id="ip-api-command" data-client-ip="{{.ClientIP}}"></pre>
|
||||
<pre id="ip-api-answer" class="loading">Loading...</pre>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer">
|
||||
@@ -584,6 +604,27 @@
|
||||
document.getElementById('ip-input').value = '';
|
||||
});
|
||||
|
||||
// IP information API card: show the curl command that asks /ip/ about
|
||||
// the visitor's own address, then make that same request and show the
|
||||
// JSON it answers, an error answer such as a 404 included. The answer
|
||||
// holds outside data, so it is set with textContent, never innerHTML.
|
||||
const ipAPICommand = document.getElementById('ip-api-command');
|
||||
const ipAPIAnswer = document.getElementById('ip-api-answer');
|
||||
const ipAPIURL = window.location.origin + '/ip/' + ipAPICommand.dataset.clientIp;
|
||||
|
||||
ipAPICommand.textContent = 'curl ' + ipAPIURL;
|
||||
|
||||
fetch(ipAPIURL)
|
||||
.then(response => response.json())
|
||||
.then(answer => {
|
||||
ipAPIAnswer.className = '';
|
||||
ipAPIAnswer.textContent = JSON.stringify(answer, null, 2);
|
||||
})
|
||||
.catch(error => {
|
||||
ipAPIAnswer.className = 'error';
|
||||
ipAPIAnswer.textContent = 'Error: ' + error.message;
|
||||
});
|
||||
|
||||
// Initial load and refresh stats every REFRESH_PERIOD_MS. The freshness
|
||||
// check runs every second on its own, so a request that never returns
|
||||
// still turns the spinner into "stale".
|
||||
|
||||
@@ -10,13 +10,14 @@ import (
|
||||
"git.eeqj.de/sneak/routewatch/internal/templates"
|
||||
)
|
||||
|
||||
// renderPage renders a page with the data every page needs.
|
||||
// renderPage renders a page with the data every page needs, and the visitor's
|
||||
// address, which the home page also needs.
|
||||
func renderPage(t *testing.T, tmpl *template.Template) string {
|
||||
t.Helper()
|
||||
|
||||
var page bytes.Buffer
|
||||
|
||||
err := tmpl.Execute(&page, struct{ CSPNonce string }{})
|
||||
err := tmpl.Execute(&page, struct{ CSPNonce, ClientIP string }{})
|
||||
if err != nil {
|
||||
t.Fatalf("rendering the page: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user