release: v2.11.2
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 2m0s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 31s

This commit is contained in:
lzstealth committed 2026-09-05 18:14:38 +01:00
1 parent 7fec2154e0
commit c4ae69d25f
40 files changed
+314 -352

No files matched your search

+9 -6
View File
@@ -1,7 +1,8 @@
// Admin account route registration and profile helpers.
const { fetchAppSettings } = require('#src/data/app-settings');
const { renderAccountEmailTemplate } = require('#src/data/account-email-templates');
const { formatAccountEmailExpiry, renderAccountEmailTemplate } = require('#src/data/account-email-templates');
const { formatUserAgentLabel } = require('#src/data/audit-log');
module.exports = function registerAccountRoutes(app, deps) {
const pool = deps.pool;
@@ -59,9 +60,10 @@ module.exports = function registerAccountRoutes(app, deps) {
const settings = await fetchAppSettings(pool);
if (!settings['email.smtp_enabled'] || typeof sendAccountEmail !== 'function') return res.status(400).send('Email delivery is not configured.');
const token = createOneTimeToken();
await pool.query('UPDATE a_users SET pending_email = ?, pending_email_token_hash = ?, pending_email_expires_at = DATE_ADD(NOW(), INTERVAL 30 MINUTE) WHERE id = ?', [email, hashSessionToken(token), req.currentUser.id]);
const expiryMinutes = Number(settings['email.verification_expiry_minutes']);
await pool.query('UPDATE a_users SET pending_email = ?, pending_email_token_hash = ?, pending_email_expires_at = DATE_ADD(NOW(), INTERVAL ' + expiryMinutes + ' MINUTE) WHERE id = ?', [email, hashSessionToken(token), req.currentUser.id]);
const url = getRequestOrigin(req) + '/verify-email?token=' + encodeURIComponent(token);
await sendAccountEmail(settings, Object.assign({ to: email }, renderAccountEmailTemplate(settings['email.verification_subject'], settings['email.verification_body'], { url: url, username: req.currentUser.username, display_name: req.currentUser.name, email: email, action_alignment: settings['email.verification_button_alignment'], action_label: settings['email.verification_button_text'] })));
await sendAccountEmail(settings, Object.assign({ to: email }, renderAccountEmailTemplate(settings['email.verification_subject'], settings['email.verification_body'], { url: url, username: req.currentUser.username, display_name: req.currentUser.name, email: email, expiry_time: formatAccountEmailExpiry(expiryMinutes, 'minutes'), action_alignment: settings['email.verification_button_alignment'], action_label: settings['email.verification_button_text'] })));
if (typeof recordRequestAuditEvent === 'function') await recordRequestAuditEvent(pool, req, { category: 'users', eventType: 'user.email_change_requested', actorUserId: req.currentUser.id, targetType: 'user', targetId: req.currentUser.id, targetLabel: email });
res.redirect('/account?message=' + encodeURIComponent('Check your new email address for a verification link.'));
} catch (error) {
@@ -87,7 +89,7 @@ module.exports = function registerAccountRoutes(app, deps) {
id: Number(session.id),
isCurrent: Boolean(tokenHash && session.session_hash === tokenHash),
ipAddress: String(session.ip_address || 'Unknown'),
userAgent: String(session.user_agent || 'Unknown browser'),
userAgent: formatUserAgentLabel(session.user_agent) || 'Unknown browser',
createdAtLabel: formatDashboardDate(session.created_at),
lastUsedAtLabel: formatDashboardDate(session.last_used_at),
expiresAtLabel: formatDashboardDate(session.expires_at)
@@ -134,9 +136,10 @@ module.exports = function registerAccountRoutes(app, deps) {
await pool.query('UPDATE a_users SET pending_email = NULL, pending_email_token_hash = NULL, pending_email_expires_at = NULL WHERE id = ?', [user.id]);
} else {
const token = createOneTimeToken();
await pool.query('UPDATE a_users SET pending_email = ?, pending_email_token_hash = ?, pending_email_expires_at = DATE_ADD(NOW(), INTERVAL 30 MINUTE) WHERE id = ?', [email, hashSessionToken(token), user.id]);
const expiryMinutes = Number(settings['email.verification_expiry_minutes']);
await pool.query('UPDATE a_users SET pending_email = ?, pending_email_token_hash = ?, pending_email_expires_at = DATE_ADD(NOW(), INTERVAL ' + expiryMinutes + ' MINUTE) WHERE id = ?', [email, hashSessionToken(token), user.id]);
const url = getRequestOrigin(req) + '/verify-email?token=' + encodeURIComponent(token);
await sendAccountEmail(settings, Object.assign({ to: email }, renderAccountEmailTemplate(settings['email.verification_subject'], settings['email.verification_body'], { url: url, username: req.currentUser.username, display_name: req.currentUser.name, email: email, action_alignment: settings['email.verification_button_alignment'], action_label: settings['email.verification_button_text'] })));
await sendAccountEmail(settings, Object.assign({ to: email }, renderAccountEmailTemplate(settings['email.verification_subject'], settings['email.verification_body'], { url: url, username: req.currentUser.username, display_name: req.currentUser.name, email: email, expiry_time: formatAccountEmailExpiry(expiryMinutes, 'minutes'), action_alignment: settings['email.verification_button_alignment'], action_label: settings['email.verification_button_text'] })));
}
}
if (emailChanged && typeof recordRequestAuditEvent === 'function') await recordRequestAuditEvent(pool, req, { category: 'users', eventType: email ? 'user.email_change_requested' : 'user.email_cleared', actorUserId: user.id, targetType: 'user', targetId: user.id, targetLabel: email || user.email, details: { previousEmail: confirmedEmail || null, email: email || null, verificationRequired: Boolean(email) } });