Allow /stats from LAN/private IP ranges
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
- `lastHour`: total visits and unique visitors in the last 60 minutes.
|
||||
- `last5Days`: daily visits and unique visitors for the last 5 UTC calendar days.
|
||||
- Wired visit recording to `GET /api/catalog` so app opens contribute to stats.
|
||||
- Updated `/stats` access control to allow localhost and LAN/private IP clients, while still blocking public internet IPs.
|
||||
|
||||
## 0.1.0 - 2026-03-25
|
||||
- Created initial frontend-only React + TypeScript project scaffold with Vite.
|
||||
|
||||
@@ -26,7 +26,7 @@ A React + TypeScript app with a local Node + SQLite backend for planning what to
|
||||
- Visits grouped by country
|
||||
- Last hour totals (`visits`, `uniqueVisitors`)
|
||||
- Last 5 calendar days (`visits`, `uniqueVisitors` per day)
|
||||
- `/stats` is localhost-only at backend level (non-local requests receive `403`).
|
||||
- `/stats` is restricted at backend level to localhost and LAN/private IP ranges only (public requests receive `403`).
|
||||
|
||||
## Project Structure
|
||||
- `frontend/`: Vite + React app (`frontend/src`, `frontend/index.html`)
|
||||
|
||||
@@ -236,7 +236,44 @@ function getRequestIp(request) {
|
||||
|
||||
function isLocalRequest(request) {
|
||||
const ip = getRequestIp(request);
|
||||
return ip === '127.0.0.1' || ip === '::1' || ip === '';
|
||||
if (!ip || ip === '127.0.0.1' || ip === '::1') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ip.includes(':')) {
|
||||
const normalized = ip.toLowerCase();
|
||||
return (
|
||||
normalized.startsWith('fc') ||
|
||||
normalized.startsWith('fd') ||
|
||||
normalized.startsWith('fe80')
|
||||
);
|
||||
}
|
||||
|
||||
const parts = ip.split('.');
|
||||
if (parts.length !== 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const octets = parts.map((part) => Number(part));
|
||||
if (octets.some((octet) => !Number.isInteger(octet) || octet < 0 || octet > 255)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const [a, b] = octets;
|
||||
if (a === 10) {
|
||||
return true;
|
||||
}
|
||||
if (a === 172 && b >= 16 && b <= 31) {
|
||||
return true;
|
||||
}
|
||||
if (a === 192 && b === 168) {
|
||||
return true;
|
||||
}
|
||||
if (a === 169 && b === 254) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function hashVisitorId(ip, userAgent) {
|
||||
|
||||
Reference in New Issue
Block a user