agregado de nuevos usuarios listo
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import express from 'express';
|
||||
import morgan from 'morgan';
|
||||
import fs from 'fs/promises';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import http from 'http';
|
||||
import dgram from 'dgram';
|
||||
import radius from 'radius';
|
||||
|
||||
@@ -21,10 +23,18 @@ const MAX_REQUESTS = parseInt(process.env.MAX_REQUESTS || '200', 10);
|
||||
const RADIUS_HOST = process.env.RADIUS_HOST || 'freeradius';
|
||||
const RADIUS_AUTH_PORT = parseInt(process.env.RADIUS_AUTH_PORT || '1812', 10);
|
||||
const RADIUS_SECRET = process.env.RADIUS_SECRET || process.env.RADIUS_SHARED_SECRET || 'tamosbien';
|
||||
const DOCKER_SOCK = process.env.DOCKER_SOCK || '/var/run/docker.sock';
|
||||
const FREERADIUS_CONTAINER = process.env.FREERADIUS_CONTAINER || 'radiusnucleo-freeradius-1';
|
||||
|
||||
// In-memory request store + SSE clients
|
||||
const requests = [];
|
||||
// In-memory users: username -> { password, vlan }
|
||||
const users = new Map([
|
||||
['user1', { password: 'contra1', vlan: '2' }],
|
||||
['user2', { password: 'contra2', vlan: '3' }],
|
||||
]);
|
||||
const sseClients = new Set();
|
||||
let radiusReloading = false;
|
||||
|
||||
function pushRequest(rec) {
|
||||
requests.push(rec);
|
||||
@@ -36,6 +46,60 @@ function pushRequest(rec) {
|
||||
}
|
||||
}
|
||||
|
||||
function broadcastStatus(payload) {
|
||||
const ev = `event: status\n` + `data: ${JSON.stringify(payload)}\n\n`;
|
||||
for (const res of sseClients) { try { res.write(ev); } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
const AUTH_FILE = process.env.AUTH_FILE || '/shared/authorize';
|
||||
|
||||
async function persistUsersToFreeradius() {
|
||||
try {
|
||||
const header = '# Managed by Node dashboard; do not edit manually\n';
|
||||
const blocks = [];
|
||||
for (const [username, { password, vlan }] of users.entries()) {
|
||||
const v = String(vlan || VLAN_ID);
|
||||
blocks.push(`${username} Cleartext-Password := "${password}"
|
||||
Tunnel-Type = VLAN,
|
||||
Tunnel-Medium-Type = IEEE-802,
|
||||
Tunnel-Private-Group-Id = "${v}"\n`);
|
||||
}
|
||||
await fs.writeFile(AUTH_FILE, header + blocks.join('\n'));
|
||||
// Trigger FreeRADIUS reload via Docker API (HUP)
|
||||
triggerRadiusReload().catch(() => {});
|
||||
} catch (e) {
|
||||
console.error('Failed to persist users to FreeRADIUS files:', e);
|
||||
}
|
||||
}
|
||||
|
||||
async function triggerRadiusReload() {
|
||||
try {
|
||||
radiusReloading = true;
|
||||
broadcastStatus({ radius_reloading: true });
|
||||
// Call Docker Engine API over unix socket: POST /containers/{id}/kill?signal=HUP
|
||||
await new Promise((resolve, reject) => {
|
||||
const req = http.request({
|
||||
method: 'POST',
|
||||
socketPath: DOCKER_SOCK,
|
||||
path: `/v1.41/containers/${encodeURIComponent(FREERADIUS_CONTAINER)}/kill?signal=HUP`,
|
||||
}, (res) => {
|
||||
res.resume();
|
||||
res.on('end', resolve);
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('Failed to HUP FreeRADIUS:', e?.message || e);
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
radiusReloading = false;
|
||||
broadcastStatus({ radius_reloading: false });
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: standard Accept with VLAN + bandwidth
|
||||
function buildAcceptPayload(extra = {}) {
|
||||
return {
|
||||
@@ -105,12 +169,9 @@ app.post('/authorize-inner', (req, res) => {
|
||||
console.log(JSON.stringify(req.body, null, 2));
|
||||
|
||||
const attrs = normalizeAttributes(req.body);
|
||||
const users = {
|
||||
'user1': 'contra1',
|
||||
'user2': 'contra2',
|
||||
};
|
||||
const username = (attrs['User-Name'] || '').toString();
|
||||
const password = users[username];
|
||||
const entry = users.get(username);
|
||||
const password = entry?.password;
|
||||
|
||||
if (!password) {
|
||||
pushRequest({
|
||||
@@ -133,12 +194,43 @@ app.post('/authorize-inner', (req, res) => {
|
||||
});
|
||||
|
||||
return res.status(200).json({
|
||||
control: {
|
||||
'Cleartext-Password': password,
|
||||
},
|
||||
control: [
|
||||
{ name: 'Cleartext-Password', value: String(password) }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
// Post-auth: return reply attributes like VLAN based on user mapping
|
||||
app.post('/post-auth', (req, res) => {
|
||||
const attrs = normalizeAttributes(req.body);
|
||||
const username = (attrs['User-Name'] || '').toString();
|
||||
const vlan = users.get(username)?.vlan || VLAN_ID;
|
||||
return res.status(200).json({
|
||||
reply: [
|
||||
{ name: 'Tunnel-Type', value: 'VLAN' },
|
||||
{ name: 'Tunnel-Medium-Type', value: 'IEEE-802' },
|
||||
{ name: 'Tunnel-Private-Group-Id', value: String(vlan) },
|
||||
{ name: 'WISPr-Bandwidth-Max-Down', value: String(MAX_DOWN) },
|
||||
{ name: 'WISPr-Bandwidth-Max-Up', value: String(MAX_UP) }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
// Users API
|
||||
app.get('/api/users', (req, res) => {
|
||||
const items = Array.from(users.entries()).map(([username, { password, vlan }]) => ({ username, password, vlan }));
|
||||
res.json({ items });
|
||||
});
|
||||
|
||||
app.post('/api/users', (req, res) => {
|
||||
const { username, password, vlan } = req.body || {};
|
||||
if (!username || !password) return res.status(400).json({ ok: false, error: 'username and password required' });
|
||||
const vlanStr = vlan ? String(vlan) : VLAN_ID;
|
||||
users.set(String(username), { password: String(password), vlan: vlanStr });
|
||||
persistUsersToFreeradius().then(() => console.log('Users synced to FreeRADIUS files'));
|
||||
res.json({ ok: true });
|
||||
});
|
||||
|
||||
// API: recent requests
|
||||
app.get('/api/requests', (req, res) => {
|
||||
res.json({ items: requests.slice(-MAX_REQUESTS) });
|
||||
@@ -196,6 +288,9 @@ app.get('/events', (req, res) => {
|
||||
// send a hello event
|
||||
res.write(`event: hello\n`);
|
||||
res.write(`data: {"ok":true}\n\n`);
|
||||
// send initial status
|
||||
res.write(`event: status\n`);
|
||||
res.write(`data: ${JSON.stringify({ radius_reloading: radiusReloading })}\n\n`);
|
||||
sseClients.add(res);
|
||||
req.on('close', () => sseClients.delete(res));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user