A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys, Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun VPN routing, and a web dashboard to manage it all. Free & open forever to self-host; optional paid hosted services fund it. See PROMISE.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
47 lines
1.4 KiB
JavaScript
Executable File
47 lines
1.4 KiB
JavaScript
Executable File
const fs = require('fs');
|
|
const path = require('path');
|
|
const crypto = require('crypto');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
|
|
const AUTH_FILE = path.join(__dirname, '..', '..', 'frontend', '.auth.json');
|
|
|
|
let authData = null;
|
|
|
|
async function initAuth(fileConfig) {
|
|
if (fs.existsSync(AUTH_FILE)) {
|
|
authData = JSON.parse(fs.readFileSync(AUTH_FILE, 'utf8'));
|
|
console.log('[Auth] Loaded existing credentials for user:', authData.username);
|
|
} else {
|
|
const username = fileConfig.CFG_WEBUI_USERNAME || 'admin';
|
|
const password = fileConfig.CFG_WEBUI_PASSWORD || 'changeme';
|
|
console.log('[Auth] Creating auth credentials for user:', username);
|
|
const passwordHash = await bcrypt.hash(password, 12);
|
|
const jwtSecret = crypto.randomBytes(32).toString('hex');
|
|
authData = { username, passwordHash, jwtSecret };
|
|
fs.writeFileSync(AUTH_FILE, JSON.stringify(authData, null, 2), 'utf8');
|
|
}
|
|
}
|
|
|
|
function generateToken(username) {
|
|
return jwt.sign({ sub: username }, authData.jwtSecret, { expiresIn: '30d' });
|
|
}
|
|
|
|
function verifyToken(token) {
|
|
try {
|
|
return jwt.verify(token, authData.jwtSecret);
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
async function verifyPassword(plain, hash) {
|
|
return bcrypt.compare(plain, hash);
|
|
}
|
|
|
|
function getCredentials() {
|
|
return authData;
|
|
}
|
|
|
|
module.exports = { initAuth, generateToken, verifyToken, verifyPassword, getCredentials };
|