--- index.html --- xxxx — Members
MEMBERS

xxxx — Members

Security & Data Notice

For security purposes this site may log limited technical data (e.g., request timestamp, your approximate location derived from IP, and browser metadata). Logged data is stored securely on the site owner’s server and is used solely for abuse mitigation, blocking, and lawful reporting. No personal data is shared with third parties without a legal obligation.

Security Policy — click to expand
  • We only log minimal technical metadata for security and abuse prevention.
  • Logs are stored on a private server with restricted access.
  • We do not share IPs publicly. Any reports to law enforcement will be handled through proper channels.
  • If you believe your data was logged in error, contact the site admin to request removal.
--- tos.html --- Terms of Service

Terms of Service

Welcome to xxxx. By using this site you agree to the following terms...

  1. Do not abuse the platform.
  2. Respect other members.
  3. Site owner may collect limited technical data for security purposes as described in the Privacy Policy.

For a complete, legally vetted terms of service please consult a lawyer. This is a template.

--- privacy.html --- Privacy Policy

Privacy Policy

This site collects minimal technical information for security and abuse prevention. Data types logged may include:

Data is stored on a private server. If you need access to data about you, contact the site administrator.

Note: This is a template. If you operate commercially or in regulated jurisdictions, consult legal counsel.

--- server.js --- // Simple secure logging backend (Node.js + Express) // Features: // - /api/log endpoint to record events server-side (IP stored in SQLite) // - Rate-limiting to prevent spam // - Optional webhook alerts that do NOT include raw IPs (only high-level alerts) const express = require('express'); const rateLimit = require('express-rate-limit'); const helmet = require('helmet'); const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const fetch = require('node-fetch'); const app = express(); const PORT = process.env.PORT || 3000; // CONFIG: change WEBHOOK_URL if you want safe alerts (recommended: create a new one that is private). // Alerts sent to webhook will NOT include raw IPs. They will include only an admin-friendly message. const WEBHOOK_URL = process.env.WEBHOOK_URL || ''; // Init DB const dbFile = path.join(__dirname,'visits.db'); const db = new sqlite3.Database(dbFile); db.serialize(()=>{ db.run(`CREATE TABLE IF NOT EXISTS visits (id INTEGER PRIMARY KEY AUTOINCREMENT, ip TEXT, action TEXT, memberId INTEGER, ua TEXT, path TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP)`); }); // Middleware app.use(helmet()); app.use(express.json({limit:'8kb'})); app.use(express.static(path.join(__dirname))); // serve index.html, tos.html, privacy.html const limiter = rateLimit({windowMs:60*1000,max:60,standardHeaders:true,legacyHeaders:false}); app.use(limiter); function getIp(req){ // trust proxy if behind a real proxy that sets X-Forwarded-For; configure your hosting accordingly const forwarded = req.headers['x-forwarded-for']; if(forwarded){ return forwarded.split(',')[0].trim(); } return req.socket.remoteAddress; } app.post('/api/log', (req,res)=>{ try{ const ip = getIp(req); const ua = req.get('User-Agent') || ''; const pathReq = req.get('Referer') || (req.body.path||''); const action = req.body.action || 'visit'; const memberId = req.body.memberId || null; // Store full IP on server-side DB only. DO NOT forward IP to external services. const stmt = db.prepare('INSERT INTO visits (ip,action,memberId,ua,path) VALUES (?,?,?,?,?)'); stmt.run(ip,action,memberId,ua,pathReq); stmt.finalize(); // Optional safe webhook alert: send a minimal message WITHOUT IPs. if(WEBHOOK_URL){ const payload = {content:`[ALERT] ${action} occurred on your site${memberId?(' — memberId:'+memberId):''}. Check server logs for details.`}; // Fire-and-forget, do not block response fetch(WEBHOOK_URL,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}).catch(()=>{}); } res.json({ok:true}); }catch(err){ console.error('log error',err); res.status(500).json({ok:false}); } }); // Admin-only route to view latest logs (protected via simple token for demo; replace with real auth in production) app.get('/admin/logs', (req,res)=>{ const token = req.query.token||''; if(token !== process.env.ADMIN_TOKEN){ return res.status(401).send('unauthorized'); } db.all('SELECT id,ip,action,memberId,ua,path,created_at FROM visits ORDER BY id DESC LIMIT 200',[],(err,rows)=>{ if(err) return res.status(500).send('db error'); res.json(rows); }) }); app.listen(PORT,()=>console.log('Server listening on',PORT)); --- README.md --- # Biosite + Secure Logging Backend This package includes: - `index.html` — the members frontend - `tos.html` / `privacy.html` — legal pages - `server.js` — Node.js backend that logs visits securely to a local SQLite DB ## Quick start 1. Install Node.js (14+) 2. Create a folder and place `server.js`, `index.html`, `tos.html`, `privacy.html` into it. 3. `npm init -y` 4. `npm install express express-rate-limit helmet sqlite3 node-fetch` 5. (Optional) Set `ADMIN_TOKEN` and `WEBHOOK_URL` env vars. 6. `node server.js` 7. Visit `http://localhost:3000/index.html` ## Notes on privacy & webhook - The server stores IP addresses in `visits.db` (SQLite) locally. You should protect the server and backups. - If you set `WEBHOOK_URL`, the server will send a **minimal** alert message to that webhook but it will **not** include IP addresses or other personal data — only a short notification. This maintains privacy while letting you know something happened. - For lawful sharing with law enforcement, export logs from the server and provide through secure channels. --- end ---