[Fix]: Update old config mentions and plug missing ones

This commit is contained in:
ClaraCrazy 2026-01-05 06:19:59 +01:00
parent 0c8db0b597
commit 8151587036
No known key found for this signature in database
GPG key ID: EBBC896ACB497011
10 changed files with 103 additions and 184 deletions

View file

@ -1,3 +1,5 @@
const templateContext = require('../template-context')
function checkLockAccess(req, res, next) {
const inboxLock = req.app.get('inboxLock')
const address = req.params.address
@ -21,14 +23,10 @@ function checkLockAccess(req, res, next) {
const unlockError = req.session ? req.session.unlockError : undefined
if (req.session) delete req.session.unlockError
return res.render('error', {
purgeTime: require('../../../application/helper').prototype.purgeTimeElemetBuilder(),
address: address,
message: 'This inbox is locked by another user. Only the owner can access it.',
branding: req.app.get('config').http.branding,
currentUser: req.session && req.session.username,
authEnabled: req.app.get('config').user.authEnabled
})
return res.render('error', templateContext.build(req, {
title: 'Access Denied',
message: 'This inbox is locked by another user. Only the owner can access it.'
}))
}
// Update last access if they have access and are authenticated

View file

@ -3,6 +3,7 @@ const express = require('express')
const router = express.Router()
const { requireAuth } = require('../middleware/auth')
const { body, validationResult } = require('express-validator')
const templateContext = require('../template-context')
// GET /account - Account dashboard
router.get('/account', requireAuth, async(req, res) => {
@ -26,25 +27,20 @@ router.get('/account', requireAuth, async(req, res) => {
const config = req.app.get('config')
const stats = userRepository.getUserStats(req.session.userId, config.user)
// Get purge time for footer
const purgeTime = helper.purgeTimeElemetBuilder()
const successMessage = req.session.accountSuccess
const errorMessage = req.session.accountError
delete req.session.accountSuccess
delete req.session.accountError
res.render('account', {
res.render('account', templateContext.build(req, {
title: 'Account Dashboard',
username: req.session.username,
forwardEmails,
lockedInboxes,
stats,
branding: config.http.features.branding || ['48hr.email', 'Service', 'https://example.com'],
purgeTime: purgeTime,
smtpEnabled: config.email.features.smtp,
successMessage: req.session.accountSuccess,
errorMessage: req.session.accountError
})
// Clear flash messages
delete req.session.accountSuccess
delete req.session.accountError
successMessage,
errorMessage
}))
} catch (error) {
console.error('Account page error:', error)
res.status(500).render('error', {

View file

@ -4,10 +4,7 @@ const { body, validationResult } = require('express-validator')
const debug = require('debug')('48hr-email:auth-routes')
const { redirectIfAuthenticated } = require('../middleware/auth')
const config = require('../../../application/config')
const Helper = require('../../../application/helper')
const helper = new Helper()
const purgeTime = helper.purgeTimeElemetBuilder()
const templateContext = require('../template-context')
// Simple in-memory rate limiters for registration and login
const registrationRateLimitStore = new Map()
@ -96,21 +93,13 @@ router.use((req, res, next) => {
// GET /auth - Show unified auth page (login or register)
router.get('/auth', redirectIfAuthenticated, (req, res) => {
const config = req.app.get('config')
const errorMessage = req.session.errorMessage
const successMessage = req.session.successMessage
// Clear messages after reading
delete req.session.errorMessage
delete req.session.successMessage
res.render('auth', {
res.render('auth', templateContext.build(req, {
title: `Login or Register | ${(config.http.features.branding || ['48hr.email'])[0]}`,
branding: config.http.features.branding || ['48hr.email', 'Service', 'https://example.com'],
purgeTime: purgeTime,
smtpEnabled: config.email.features.smtp,
errorMessage,
successMessage
})
}))
})
// POST /register - Process registration

View file

@ -1,13 +1,9 @@
const express = require('express')
const router = new express.Router()
const config = require('../../../application/config')
const Helper = require('../../../application/helper')
const helper = new(Helper)
const templateContext = require('../template-context')
const debug = require('debug')('48hr-email:routes')
const purgeTime = helper.purgeTimeElemetBuilder()
router.get('/:address/:errorCode', async(req, res, next) => {
try {
const mailProcessingService = req.app.get('mailProcessingService')
@ -21,14 +17,11 @@ router.get('/:address/:errorCode', async(req, res, next) => {
debug(`Rendering error page ${errorCode} with message: ${message}`)
const branding = config.http.features.branding || ['48hr.email', 'Service', 'https://example.com']
res.status(errorCode)
res.render('error', {
res.render('error', templateContext.build(req, {
title: `${branding[0]} | ${errorCode}`,
purgeTime: purgeTime,
address: req.params.address,
message: message,
status: errorCode,
branding: branding
})
status: errorCode
}))
} catch (error) {
debug('Error loading error page:', error.message)
console.error('Error while loading error page', error)

View file

@ -6,6 +6,7 @@ const debug = require('debug')('48hr-email:routes')
const config = require('../../../application/config')
const Helper = require('../../../application/helper')
const CryptoDetector = require('../../../application/crypto-detector')
const templateContext = require('../template-context')
const helper = new(Helper)
const cryptoDetector = new CryptoDetector()
const { checkLockAccess } = require('../middleware/lock')
@ -105,68 +106,11 @@ router.get('^/:address([^@/]+@[^@/]+)', sanitizeAddress, validateDomain, optiona
throw new Error('Mail processing service not available')
}
debug(`Inbox request for ${req.params.address}`)
const inboxLock = req.app.get('inboxLock')
// Check lock status
const isLocked = inboxLock && inboxLock.isLocked(req.params.address)
const userId = req.session && req.session.userId
const isAuthenticated = req.session && req.session.isAuthenticated
// Check if user has access (either owns the lock or has session access)
const hasAccess = isAuthenticated && userId && inboxLock ?
(inboxLock.isLockedByUser(req.params.address, userId) || req.session.lockedInbox === req.params.address) :
(req.session && req.session.lockedInbox === req.params.address)
// Get user's verified emails if logged in
let userForwardEmails = []
if (req.session && req.session.userId) {
const userRepository = req.app.get('userRepository')
if (userRepository) {
userForwardEmails = userRepository.getForwardEmails(req.session.userId)
}
}
// Pull any lock error from session and clear it after reading
const lockError = req.session ? req.session.lockError : undefined
const unlockErrorSession = req.session ? req.session.unlockError : undefined
const errorMessage = req.session ? req.session.errorMessage : undefined
if (req.session) {
delete req.session.lockError
delete req.session.unlockError
delete req.session.errorMessage
}
// Check for forward all success flag
const forwardAllSuccess = req.query.forwardedAll ? parseInt(req.query.forwardedAll) : null
// Check for verification sent flag
const verificationSent = req.query.verificationSent === 'true'
const verificationEmail = req.query.email || ''
res.render('inbox', {
res.render('inbox', templateContext.build(req, {
title: `${(config.http.features.branding || ['48hr.email'])[0]} | ` + req.params.address,
purgeTime: purgeTime,
address: req.params.address,
mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
branding: config.http.branding,
authEnabled: config.user.authEnabled,
smtpEnabled: config.email.features.smtp,
isAuthenticated: req.session && req.session.userId ? true : false,
userForwardEmails: userForwardEmails,
isLocked: isLocked,
hasAccess: hasAccess,
unlockError: unlockErrorSession,
locktimer: config.user.lockReleaseHours,
error: lockError,
redirectTo: req.originalUrl,
expiryTime: config.email.purgeTime.time,
expiryUnit: config.email.purgeTime.unit,
refreshInterval: config.imap.refreshIntervalSeconds,
errorMessage: errorMessage,
forwardAllSuccess: forwardAllSuccess,
verificationSent: verificationSent,
verificationEmail: verificationEmail
})
mailSummaries: mailProcessingService.getMailSummaries(req.params.address)
}))
} catch (error) {
debug(`Error loading inbox for ${req.params.address}:`, error.message)
console.error('Error while loading inbox', error)
@ -201,58 +145,13 @@ router.get(
const cryptoAttachments = cryptoDetector.detectCryptoAttachments(mail.attachments)
debug(`Found ${cryptoAttachments.length} cryptographic attachments`)
const inboxLock = req.app.get('inboxLock')
const isLocked = inboxLock && inboxLock.isLocked(req.params.address)
const userId = req.session && req.session.userId
const isAuthenticated = req.session && req.session.isAuthenticated
// Check if user has access (either owns the lock or has session access)
const hasAccess = isAuthenticated && userId && inboxLock ?
(inboxLock.isLockedByUser(req.params.address, userId) || req.session.lockedInbox === req.params.address) :
(req.session && req.session.lockedInbox === req.params.address)
// Get user's verified emails if logged in
let userForwardEmails = []
if (req.session && req.session.userId) {
const userRepository = req.app.get('userRepository')
if (userRepository) {
userForwardEmails = userRepository.getForwardEmails(req.session.userId)
}
}
// Pull error message from session and clear it
const errorMessage = req.session ? req.session.errorMessage : undefined
if (req.session) {
delete req.session.errorMessage
}
// Check for forward success flag
const forwardSuccess = req.query.forwarded === 'true'
// Check for verification sent flag
const verificationSent = req.query.verificationSent === 'true'
const verificationEmail = req.query.email || ''
debug(`Rendering email view for UID ${req.params.uid}`)
res.render('mail', {
res.render('mail', templateContext.build(req, {
title: mail.subject + " | " + req.params.address,
purgeTime: purgeTime,
address: req.params.address,
mail,
cryptoAttachments: cryptoAttachments,
uid: req.params.uid,
branding: config.http.features.branding || ['48hr.email', 'Service', 'https://example.com'],
authEnabled: config.user.authEnabled,
smtpEnabled: config.email.features.smtp,
isAuthenticated: req.session && req.session.userId ? true : false,
userForwardEmails: userForwardEmails,
isLocked: isLocked,
hasAccess: hasAccess,
errorMessage: errorMessage,
forwardSuccess: forwardSuccess,
verificationSent: verificationSent,
verificationEmail: verificationEmail
})
uid: req.params.uid
}))
} else {
debug(`Email ${req.params.uid} not found for ${req.params.address}`)
req.session.errorMessage = 'This mail could not be found. It either does not exist or has been deleted from our servers!'
@ -424,11 +323,11 @@ router.get(
// Emails are immutable, cache if found
res.set('Cache-Control', 'private, max-age=600')
debug(`Rendering raw email view for UID ${req.params.uid}`)
res.render('raw', {
res.render('raw', templateContext.build(req, {
title: req.params.uid + " | raw | " + req.params.address,
mail: rawMail,
decoded: decodedMail
})
}))
} else {
debug(`Raw email ${uid} not found for ${req.params.address}`)
req.session.errorMessage = 'This mail could not be found. It either does not exist or has been deleted from our servers!'

View file

@ -1,6 +1,7 @@
const express = require('express')
const router = new express.Router()
const debug = require('debug')('48hr-email:stats-routes')
const templateContext = require('../template-context')
// GET /stats - Statistics page with lazy loading
router.get('/', async(req, res) => {
@ -16,10 +17,7 @@ router.get('/', async(req, res) => {
return res.redirect(redirectUrl)
}
const Helper = require('../../../application/helper')
const helper = new Helper()
const branding = config.http.features.branding || ['48hr.email', 'Service', 'https://example.com']
const purgeTime = helper.purgeTimeElemetBuilder()
// Return page with placeholder data immediately - real data loads via JS
const placeholderStats = {
@ -48,15 +46,11 @@ router.get('/', async(req, res) => {
debug(`Stats page requested - returning with lazy loading`)
res.render('stats', {
res.render('stats', templateContext.build(req, {
title: `Statistics | ${branding[0]}`,
branding: branding,
purgeTime: purgeTime,
stats: placeholderStats,
authEnabled: config.user.authEnabled,
currentUser: req.session && req.session.username,
lazyLoad: true
})
}))
} catch (error) {
debug(`Error loading stats page: ${error.message}`)
console.error('Error while loading stats page', error)

View file

@ -19,12 +19,36 @@ class TemplateContext {
* @returns {Object} Base template context
*/
getBaseContext(req) {
const inboxLock = req.app.get('inboxLock')
const address = req.params && req.params.address
const userId = req.session && req.session.userId
const isAuthenticated = !!(req.session && req.session.userId)
// Calculate lock status for current address
const isLocked = address && inboxLock ? inboxLock.isLocked(address) : false
const hasAccess = address && isAuthenticated && userId && inboxLock ?
(inboxLock.isLockedByUser(address, userId) || req.session.lockedInbox === address) :
(address && req.session && req.session.lockedInbox === address)
// Get user's verified forward emails if logged in
let userForwardEmails = []
if (isAuthenticated && userId) {
const userRepository = req.app.get('userRepository')
if (userRepository) {
userForwardEmails = userRepository.getForwardEmails(userId)
}
}
return {
// Config values
config: config,
branding: config.http.features.branding || ['48hr.email', 'Service', 'https://example.com'],
purgeTime: this.purgeTime,
purgeTimeRaw: config.email.purgeTime,
expiryTime: config.email.purgeTime.time,
expiryUnit: config.email.purgeTime.unit,
refreshInterval: config.imap.refreshIntervalSeconds,
locktimer: config.user.lockReleaseHours,
// Feature flags
authEnabled: config.user.authEnabled,
@ -32,8 +56,29 @@ class TemplateContext {
smtpEnabled: config.email.features.smtp,
showInfoSection: config.http.features.infoSection,
// User session
// User session & authentication
currentUser: req.session && req.session.username ? req.session.username : null,
isAuthenticated: isAuthenticated,
userForwardEmails: userForwardEmails,
// Lock status
isLocked: isLocked,
hasAccess: hasAccess,
// Session messages/errors (auto-clear after reading)
error: this._getAndClearSession(req, 'lockError'),
unlockError: this._getAndClearSession(req, 'unlockError'),
errorMessage: this._getAndClearSession(req, 'errorMessage'),
// Query parameters
verificationSent: req.query && req.query.verificationSent === 'true',
verificationEmail: req.query && req.query.email || '',
forwardSuccess: req.query && req.query.forwarded === 'true',
forwardAllSuccess: req.query && req.query.forwardedAll ? parseInt(req.query.forwardedAll) : null,
// Request info
redirectTo: req.originalUrl,
address: address,
// Common data
domains: this.cachedDomains,
@ -41,6 +86,17 @@ class TemplateContext {
}
}
/**
* Helper to get and clear session value
* @private
*/
_getAndClearSession(req, key) {
if (!req.session) return undefined
const value = req.session[key]
delete req.session[key]
return value
}
/**
* Merge base context with page-specific data
* @param {Object} req - Express request object

View file

@ -9,7 +9,7 @@
{% block metaTags %}
<!-- SEO Meta Tags -->
<meta name="description" content="Your temporary Inbox. Create instant throwaway email addresses to protect your privacy. No registration required. Emails auto-delete after 48 hours.">
<meta name="description" content="Your temporary Inbox. Create instant throwaway email addresses to protect your privacy. No registration required. Emails auto-delete after {{ purgeTime | raw }}.">
<meta name="keywords" content="temporary email, disposable email, throwaway email, fake email, temp mail, anonymous email, 48hr email, privacy protection, burner email">
<meta name="author" content="CrazyCo">
<meta name="robots" content="index, follow">
@ -20,7 +20,7 @@
<meta property="og:type" content="website">
<meta property="og:url" content="https://48hr.email/">
<meta property="og:title" content="48hr.email - Your temporary Inbox">
<meta property="og:description" content="Protect your privacy with free temporary email addresses. No registration required. Emails auto-delete after 48 hours.">
<meta property="og:description" content="Protect your privacy with free temporary email addresses. No registration required. Emails auto-delete after {{ purgeTime | raw }}.">
<meta property="og:image" content="https://48hr.email/images/logo.png">
<meta property="og:site_name" content="48hr.email">

View file

@ -71,12 +71,7 @@ function convertAndRound(time, unit) {
*/
exports.readablePurgeTime = function(purgeTime) {
if (!purgeTime || !purgeTime.time || !purgeTime.unit) {
// Fallback to config if not provided
if (config.email.purgeTime) {
purgeTime = config.email.purgeTime
} else {
return '48 hours'
}
purgeTime = config.email.purgeTime
}
let result = `${purgeTime.time} ${purgeTime.unit}`

View file

@ -18,12 +18,9 @@ const lockRouter = require('./routes/lock')
const authRouter = require('./routes/auth')
const accountRouter = require('./routes/account')
const statsRouter = require('./routes/stats')
const templateContext = require('./template-context')
const { sanitizeHtmlTwigFilter, readablePurgeTime } = require('./views/twig-filters')
const Helper = require('../../application/helper')
const helper = new(Helper)
const purgeTime = helper.purgeTimeElemetBuilder()
// Utility function for consistent error handling in routes
const handleRouteError = (error, req, res, next, context = 'route') => {
debug(`Error in ${context}:`, error.message)
@ -143,7 +140,9 @@ app.use(async(req, res, next) => {
app.use((req, res, next) => {
const isImapReady = req.app.get('isImapReady')
if (!isImapReady && !req.path.startsWith('/images') && !req.path.startsWith('/javascripts') && !req.path.startsWith('/stylesheets') && !req.path.startsWith('/dependencies')) {
return res.render('loading')
return res.render('loading', templateContext.build(req, {
title: 'Loading...'
}))
}
next()
})
@ -174,11 +173,11 @@ app.use(async(err, req, res, _next) => {
// Render the error page
res.status(err.status || 500)
res.render('error', {
purgeTime: purgeTime,
address: req.params && req.params.address,
branding: config.http.features.branding || ['48hr.email', 'Service', 'https://example.com']
})
res.render('error', templateContext.build(req, {
title: 'Error',
message: err.message,
status: err.status || 500
}))
} catch (renderError) {
debug('Error in error handler:', renderError.message)
console.error('Critical error in error handler', renderError)