DUNGEONS-30: add access gateway with Telegram and Discord approvals
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
47
src/http.js
Normal file
47
src/http.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import { isIP } from 'node:net';
|
||||
|
||||
export const COOKIE = 'dng_access';
|
||||
|
||||
export function readCookie(req) {
|
||||
const matches = (req.headers.cookie || '').split(';').map(v => v.trim()).filter(v => v.startsWith(`${COOKIE}=`));
|
||||
return matches.length === 1 ? matches[0].slice(COOKIE.length + 1) : '';
|
||||
}
|
||||
|
||||
export function sessionCookie(config, token, maxAge = 0) {
|
||||
return `${COOKIE}=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${maxAge}${config.secureCookie ? '; Secure' : ''}`;
|
||||
}
|
||||
|
||||
export function safeNext(value) {
|
||||
if (typeof value !== 'string' || value.length > 4096 || !value.startsWith('/') || value.startsWith('//') || /[\\\u0000-\u0020]/.test(value)) return '/';
|
||||
try {
|
||||
const decoded = decodeURIComponent(value);
|
||||
if (/[\\\u0000-\u001f]/.test(decoded)) return '/';
|
||||
const url = new URL(value, 'http://gateway.local');
|
||||
if (url.origin !== 'http://gateway.local' || url.pathname.startsWith('/_access')) return '/';
|
||||
return url.pathname + url.search + url.hash;
|
||||
} catch { return '/'; }
|
||||
}
|
||||
|
||||
export function clientIp(req, config) {
|
||||
const forwarded = req.headers['x-forwarded-for'];
|
||||
// Accept a single IP only. Forwarded chains require explicit edge normalization.
|
||||
if (config.trustProxy && typeof forwarded === 'string' && isIP(forwarded.trim())) return forwarded.trim();
|
||||
return req.socket.remoteAddress || 'unknown';
|
||||
}
|
||||
|
||||
export function sendJson(res, status, body, headers = {}) {
|
||||
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store', 'x-content-type-options': 'nosniff', ...headers });
|
||||
res.end(JSON.stringify(body));
|
||||
}
|
||||
|
||||
export async function readBody(req, maximum = 4096) {
|
||||
if (Number(req.headers['content-length']) > maximum) { const error = new Error('Request is too large.'); error.status = 413; throw error; }
|
||||
const chunks = [];
|
||||
let size = 0;
|
||||
for await (const chunk of req) {
|
||||
size += chunk.length;
|
||||
if (size > maximum) { const error = new Error('Request is too large.'); error.status = 413; throw error; }
|
||||
chunks.push(chunk);
|
||||
}
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
Reference in New Issue
Block a user