diff --git a/app.js b/app.js
index 31bb52e..1bcee6f 100644
--- a/app.js
+++ b/app.js
@@ -1,4 +1,5 @@
#!/usr/bin/env node
+
/* eslint unicorn/no-process-exit: 0 */
const config = require('./application/config')
@@ -6,7 +7,7 @@ const config = require('./application/config')
// Until node 11 adds flatmap, we use this:
require('array.prototype.flatmap').shim()
-const {app, io, server} = require('./infrastructure/web/web')
+const { app, io, server } = require('./infrastructure/web/web')
const ClientNotification = require('./infrastructure/web/client-notification')
const ImapService = require('./application/imap-service')
const MailProcessingService = require('./application/mail-processing-service')
@@ -17,58 +18,58 @@ clientNotification.use(io)
const imapService = new ImapService(config)
const mailProcessingService = new MailProcessingService(
- new MailRepository(),
- imapService,
- clientNotification,
- config
+ new MailRepository(),
+ imapService,
+ clientNotification,
+ config
)
// Put everything together:
imapService.on(ImapService.EVENT_NEW_MAIL, mail =>
- mailProcessingService.onNewMail(mail)
+ mailProcessingService.onNewMail(mail)
)
imapService.on(ImapService.EVENT_INITIAL_LOAD_DONE, () =>
- mailProcessingService.onInitialLoadDone()
+ mailProcessingService.onInitialLoadDone()
)
imapService.on(ImapService.EVENT_DELETED_MAIL, mail =>
- mailProcessingService.onMailDeleted(mail)
+ mailProcessingService.onMailDeleted(mail)
)
mailProcessingService.on('error', err => {
- console.error('error from mailProcessingService, stopping.', err)
- process.exit(1)
+ console.error('Error from mailProcessingService, stopping.', err)
+ process.exit(1)
})
imapService.on(ImapService.EVENT_ERROR, error => {
- console.error('fatal error from imap service', error)
- process.exit(1)
+ console.error('Fatal error from IMAP service', error)
+ process.exit(1)
})
app.set('mailProcessingService', mailProcessingService)
imapService.connectAndLoadMessages().catch(error => {
- console.error('fatal error from imap service', error)
- process.exit(1)
+ console.error('Fatal error from IMAP service', error)
+ process.exit(1)
})
server.on('error', error => {
- if (error.syscall !== 'listen') {
- console.error('fatal web server error', error)
- return
- }
+ if (error.syscall !== 'listen') {
+ console.error('Fatal web server error', error)
+ return
+ }
- // Handle specific listen errors with friendly messages
- switch (error.code) {
- case 'EACCES':
- console.error(
- 'Port ' + config.http.port + ' requires elevated privileges'
- )
- process.exit(1)
- case 'EADDRINUSE':
- console.error('Port ' + config.http.port + ' is already in use')
- process.exit(1)
- default:
- console.error('fatal web server error', error)
- process.exit(1)
- }
-})
+ // Handle specific listen errors with friendly messages
+ switch (error.code) {
+ case 'EACCES':
+ console.error(
+ 'Port ' + config.http.port + ' requires elevated privileges'
+ )
+ process.exit(1)
+ case 'EADDRINUSE':
+ console.error('Port ' + config.http.port + ' is already in use')
+ process.exit(1)
+ default:
+ console.error('Fatal web server error', error)
+ process.exit(1)
+ }
+})
\ No newline at end of file
diff --git a/application/imap-service.js b/application/imap-service.js
index b20a0c6..cc820d1 100644
--- a/application/imap-service.js
+++ b/application/imap-service.js
@@ -127,21 +127,18 @@ class ImapService extends EventEmitter {
this.connection.on('error', err => {
// We assume that the app will be restarted after a crash.
- console.error(
- 'got fatal error during imap operation, stop app.',
- err
- )
+ console.error('got fatal error during imap operation, stop app.', err)
this.emit('error', err)
})
await this.connection.openBox('INBOX')
- debug('connected to imap')
+ debug('Connected to imap')
}, {
retries: 5
}
)
} catch (error) {
- console.error('can not connect, even with retry, stop app', error)
+ console.error('Cant connect, even after retrying, stopping app', error)
throw error
}
}
@@ -226,7 +223,7 @@ class ImapService extends EventEmitter {
})
if (uids.length === 0) {
- debug('no mails to delete.')
+ debug('No mails to delete.')
return
}
@@ -235,7 +232,7 @@ class ImapService extends EventEmitter {
uids.forEach(uid => {
this.emit(ImapService.EVENT_DELETED_MAIL, uid)
})
- console.log(`deleted ${uids.length} old messages.`)
+ console.log(`Deleted ${uids.length} old messages.`)
}
/**
@@ -243,10 +240,10 @@ class ImapService extends EventEmitter {
* @param uid delete specific mail per UID
*/
async deleteSpecificEmail(uid) {
- debug(`deleting mails ${uid}`)
+ debug(`Deleting mails ${uid}`)
if (!this.config.email.examples.uids.includes(parseInt(uid))) {
await this.connection.deleteMessage(uid)
- debug(`deleted mail with UID: ${uid}.`)
+ debug(`Deleted mail with UID: ${uid}.`)
this.emit(ImapService.EVENT_DELETED_MAIL, uid)
}
}
@@ -297,10 +294,10 @@ class ImapService extends EventEmitter {
async fetchOneFullMail(to, uid, raw = false) {
if (!this.connection) {
// Here we 'fail fast' instead of waiting for the connection.
- throw new Error('imap connection not ready')
+ throw new Error('IMAP connection not ready')
}
- debug(`fetching full message ${uid}`)
+ debug(`Fetching full message ${uid}`)
// For security we also filter TO, so it is harder to just enumerate all messages.
const searchCriteria = [
@@ -344,7 +341,7 @@ class ImapService extends EventEmitter {
}
})
} catch (error) {
- debug('can not fetch', error)
+ debug('Cant fetch', error)
throw error
}
}
diff --git a/application/mail-processing-service.js b/application/mail-processing-service.js
index 305425b..c8d6caf 100644
--- a/application/mail-processing-service.js
+++ b/application/mail-processing-service.js
@@ -54,13 +54,13 @@ class MailProcessingService extends EventEmitter {
onInitialLoadDone() {
this.initialLoadDone = true
- console.log(`initial load done, got ${this.mailRepository.mailCount()} mails`)
+ console.log(`Initial load done, got ${this.mailRepository.mailCount()} mails`)
}
onNewMail(mail) {
if (this.initialLoadDone) {
// For now, only log messages if they arrive after the initial load
- debug('new mail for', mail.to[0])
+ debug('New mail for', mail.to[0])
}
mail.to.forEach(to => {
@@ -70,7 +70,7 @@ class MailProcessingService extends EventEmitter {
}
onMailDeleted(uid) {
- debug('mail deleted with uid', uid)
+ debug('Mail deleted with uid', uid)
this.mailRepository.removeUid(uid)
}
@@ -78,7 +78,7 @@ class MailProcessingService extends EventEmitter {
try {
await this.imapService.deleteOldMails(helper.purgeTimeStamp())
} catch (error) {
- console.log('can not delete old messages', error)
+ console.log('Cant delete old messages', error)
}
}
@@ -86,7 +86,7 @@ class MailProcessingService extends EventEmitter {
const fs = require('fs')
fs.writeFile(filename, JSON.stringify(mails), err => {
if (err) {
- console.error('can not save mails to file', err)
+ console.error('Cant save mails to file', err)
}
})
}
diff --git a/domain/mail-repository.js b/domain/mail-repository.js
index 0297d8d..a271b51 100644
--- a/domain/mail-repository.js
+++ b/domain/mail-repository.js
@@ -15,7 +15,7 @@ class MailRepository {
mails.forEach(mail => {
if (mail.to == this.config.email.examples.account && !this.config.email.examples.uids.includes(parseInt(mail.uid))) {
mails = mails.filter(m => m.uid != mail.uid)
- debug('prevented non-example email from being shown in example inbox', mail.uid)
+ debug('Prevented non-example email from being shown in example inbox', mail.uid)
}
})
return _.orderBy(mails, mail => Date.parse(mail.date), ['desc'])
@@ -43,7 +43,7 @@ class MailRepository {
.filter(mail => mail.uid === parseInt(uid) && (address ? to == address : true))
.forEach(mail => {
this.mailSummaries.remove(to, mail)
- debug('removed ', mail.date, to, mail.subject)
+ debug('Removed ', mail.date, to, mail.subject)
deleted = true
})
})
diff --git a/infrastructure/web/routes/inbox.js b/infrastructure/web/routes/inbox.js
index 400383e..db399fd 100644
--- a/infrastructure/web/routes/inbox.js
+++ b/infrastructure/web/routes/inbox.js
@@ -1,6 +1,6 @@
const express = require('express')
const router = new express.Router()
-const {param} = require('express-validator')
+const { param } = require('express-validator')
const config = require('../../../application/config')
const Helper = require('../../../application/helper')
@@ -9,182 +9,179 @@ const helper = new(Helper)
const purgeTime = helper.purgeTimeElemetBuilder()
const sanitizeAddress = param('address').customSanitizer(
- (value, {req}) => {
- return req.params.address
- .replace(/[^A-Za-z0-9_.+@-]/g, '') // Remove special characters
- .toLowerCase()
- }
+ (value, { req }) => {
+ return req.params.address
+ .replace(/[^A-Za-z0-9_.+@-]/g, '') // Remove special characters
+ .toLowerCase()
+ }
)
router.get('^/:address([^@/]+@[^@/]+)', sanitizeAddress, (req, res, _next) => {
- const mailProcessingService = req.app.get('mailProcessingService')
- res.render('inbox', {
- title: `${config.http.branding[0]} | ` + req.params.address,
- purgeTime: purgeTime,
- address: req.params.address,
- mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
- branding: config.http.branding,
- })
+ const mailProcessingService = req.app.get('mailProcessingService')
+ res.render('inbox', {
+ title: `${config.http.branding[0]} | ` + req.params.address,
+ purgeTime: purgeTime,
+ address: req.params.address,
+ mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
+ branding: config.http.branding,
+ })
})
router.get(
- '^/:address/:uid([0-9]+)',
- sanitizeAddress,
- async (req, res, next) => {
- try {
- const mailProcessingService = req.app.get('mailProcessingService')
- const mail = await mailProcessingService.getOneFullMail(
- req.params.address,
- req.params.uid
- )
- if (mail) {
- // Set a default subject if none is present
- if (!mail.subject) {
- mail.subject = 'No Subject'
- }
+ '^/:address/:uid([0-9]+)',
+ sanitizeAddress,
+ async(req, res, next) => {
+ try {
+ const mailProcessingService = req.app.get('mailProcessingService')
+ const mail = await mailProcessingService.getOneFullMail(
+ req.params.address,
+ req.params.uid
+ )
+ if (mail) {
+ // Set a default subject if none is present
+ if (!mail.subject) {
+ mail.subject = 'No Subject'
+ }
- // Emails are immutable, cache if found
- res.set('Cache-Control', 'private, max-age=600')
- res.render('mail', {
- title: mail.subject + " | " + req.params.address,
- purgeTime: purgeTime,
- address: req.params.address,
- mail,
- uid: req.params.uid,
- branding: config.http.branding,
- })
- } else {
- res.render(
- 'error',
- {
- purgeTime: purgeTime,
- address: req.params.address,
- message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
- branding: config.http.branding
+ // Emails are immutable, cache if found
+ res.set('Cache-Control', 'private, max-age=600')
+ res.render('mail', {
+ title: mail.subject + " | " + req.params.address,
+ purgeTime: purgeTime,
+ address: req.params.address,
+ mail,
+ uid: req.params.uid,
+ branding: config.http.branding,
+ })
+ } else {
+ res.render(
+ 'error', {
+ purgeTime: purgeTime,
+ address: req.params.address,
+ message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
+ branding: config.http.branding
- }
- )
- }
- } catch (error) {
- console.error('error while fetching one email', error)
- next(error)
- }
- }
+ }
+ )
+ }
+ } catch (error) {
+ console.error('Error while fetching email', error)
+ next(error)
+ }
+ }
)
router.get(
- '^/:address/delete-all',
- sanitizeAddress,
- async (req, res, next) => {
- try {
- const mailProcessingService = req.app.get('mailProcessingService')
- const mailSummaries = await mailProcessingService.getMailSummaries(req.params.address)
- for (mail in mailSummaries) {
- await mailProcessingService.deleteSpecificEmail(req.params.address, mailSummaries[mail].uid)
- }
- res.redirect(`/inbox/${req.params.address}`)
- } catch (error) {
- console.error('error while deleting email', error)
- next(error)
- }
- }
+ '^/:address/delete-all',
+ sanitizeAddress,
+ async(req, res, next) => {
+ try {
+ const mailProcessingService = req.app.get('mailProcessingService')
+ const mailSummaries = await mailProcessingService.getMailSummaries(req.params.address)
+ for (mail in mailSummaries) {
+ await mailProcessingService.deleteSpecificEmail(req.params.address, mailSummaries[mail].uid)
+ }
+ res.redirect(`/inbox/${req.params.address}`)
+ } catch (error) {
+ console.error('Error while deleting email', error)
+ next(error)
+ }
+ }
)
router.get(
- '^/:address/:uid/delete',
- sanitizeAddress,
- async (req, res, next) => {
- try {
- const mailProcessingService = req.app.get('mailProcessingService')
- await mailProcessingService.deleteSpecificEmail(req.params.address, req.params.uid)
- res.redirect(`/inbox/${req.params.address}`)
- } catch (error) {
- console.error('error while deleting email', error)
- next(error)
- }
- }
+ '^/:address/:uid/delete',
+ sanitizeAddress,
+ async(req, res, next) => {
+ try {
+ const mailProcessingService = req.app.get('mailProcessingService')
+ await mailProcessingService.deleteSpecificEmail(req.params.address, req.params.uid)
+ res.redirect(`/inbox/${req.params.address}`)
+ } catch (error) {
+ console.error('Error while deleting email', error)
+ next(error)
+ }
+ }
)
router.get(
- '^/:address/:uid/:checksum([a-f0-9]+)',
- sanitizeAddress,
- async (req, res, next) => {
- try {
- const mailProcessingService = req.app.get('mailProcessingService')
- const mail = await mailProcessingService.getOneFullMail(
- req.params.address,
- req.params.uid
- )
- var index = mail.attachments.findIndex(attachment => attachment.checksum === req.params.checksum);
- const attachment = mail.attachments[index];
- if (attachment) {
- try {
- res.set('Content-Disposition', `attachment; filename=${attachment.filename}`);
- res.set('Content-Type', attachment.contentType);
- res.send(attachment.content);
- return;
- } catch (error) {
- console.error('error while fetching attachment', error);
- next(error);
- }
- } else {
- res.render(
- 'error',
- {
- purgeTime: purgeTime,
- address: req.params.address,
- message: 'This attachment could not be found. It either does not exist or has been deleted from our servers!',
- branding: config.http.branding,
- }
- )
- }
- res.redirect(`/inbox/${req.params.address}`)
- } catch (error) {
- console.error('error while deleting email', error)
- next(error)
- }
- }
+ '^/:address/:uid/:checksum([a-f0-9]+)',
+ sanitizeAddress,
+ async(req, res, next) => {
+ try {
+ const mailProcessingService = req.app.get('mailProcessingService')
+ const mail = await mailProcessingService.getOneFullMail(
+ req.params.address,
+ req.params.uid
+ )
+ var index = mail.attachments.findIndex(attachment => attachment.checksum === req.params.checksum);
+ const attachment = mail.attachments[index];
+ if (attachment) {
+ try {
+ res.set('Content-Disposition', `attachment; filename=${attachment.filename}`);
+ res.set('Content-Type', attachment.contentType);
+ res.send(attachment.content);
+ return;
+ } catch (error) {
+ console.error('Error while fetching attachment', error);
+ next(error);
+ }
+ } else {
+ res.render(
+ 'error', {
+ purgeTime: purgeTime,
+ address: req.params.address,
+ message: 'This attachment could not be found. It either does not exist or has been deleted from our servers!',
+ branding: config.http.branding,
+ }
+ )
+ }
+ res.redirect(`/inbox/${req.params.address}`)
+ } catch (error) {
+ console.error('Error while deleting email', error)
+ next(error)
+ }
+ }
)
router.get(
- '^/:address/:uid/raw',
- sanitizeAddress,
- async (req, res, next) => {
- try {
- const mailProcessingService = req.app.get('mailProcessingService')
- mail = await mailProcessingService.getOneFullMail(
- req.params.address,
- req.params.uid,
- true
- )
- if (mail) {
- mail = mail.replace(/(?:\r\n|\r|\n)/g, '
')
- // Emails are immutable, cache if found
- res.set('Cache-Control', 'private, max-age=600')
- res.render('raw', {
- title: req.params.uid + " | raw | " + req.params.address,
- mail
- })
- } else {
- res.render(
- 'error',
- {
- purgeTime: purgeTime,
- address: req.params.address,
- message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
- branding: config.http.branding,
- }
- )
- }
- } catch (error) {
- console.error('error while fetching one email', error)
- next(error)
- }
- }
+ '^/:address/:uid/raw',
+ sanitizeAddress,
+ async(req, res, next) => {
+ try {
+ const mailProcessingService = req.app.get('mailProcessingService')
+ mail = await mailProcessingService.getOneFullMail(
+ req.params.address,
+ req.params.uid,
+ true
+ )
+ if (mail) {
+ mail = mail.replace(/(?:\r\n|\r|\n)/g, '
')
+ // Emails are immutable, cache if found
+ res.set('Cache-Control', 'private, max-age=600')
+ res.render('raw', {
+ title: req.params.uid + " | raw | " + req.params.address,
+ mail
+ })
+ } else {
+ res.render(
+ 'error', {
+ purgeTime: purgeTime,
+ address: req.params.address,
+ message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
+ branding: config.http.branding,
+ }
+ )
+ }
+ } catch (error) {
+ console.error('Error while fetching raw email', error)
+ next(error)
+ }
+ }
)
-module.exports = router
+module.exports = router
\ No newline at end of file
diff --git a/infrastructure/web/web.js b/infrastructure/web/web.js
index 09531d4..e70561b 100644
--- a/infrastructure/web/web.js
+++ b/infrastructure/web/web.js
@@ -11,7 +11,7 @@ const socketio = require('socket.io')
const config = require('../../application/config')
const inboxRouter = require('./routes/inbox')
const loginRouter = require('./routes/login')
-const {sanitizeHtmlTwigFilter} = require('./views/twig-filters')
+const { sanitizeHtmlTwigFilter } = require('./views/twig-filters')
// Init express middleware
const app = express()
@@ -24,20 +24,20 @@ const io = socketio(server)
app.set('socketio', io)
app.use(logger('dev'))
app.use(express.json())
-app.use(express.urlencoded({extended: false}))
-// View engine setup
+app.use(express.urlencoded({ extended: false }))
+ // View engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'twig')
app.set('twig options', {
- autoescape: true
+ autoescape: true
})
// Application code:
app.use(
- express.static(path.join(__dirname, 'public'), {
- immutable: true,
- maxAge: '1h'
- })
+ express.static(path.join(__dirname, 'public'), {
+ immutable: true,
+ maxAge: '1h'
+ })
)
Twig.extendFilter('sanitizeHtml', sanitizeHtmlTwigFilter)
@@ -52,18 +52,18 @@ app.use('/inbox', inboxRouter)
// Catch 404 and forward to error handler
app.use((req, res, next) => {
- next({message: 'page not found', status: 404})
+ next({ message: 'Page not found', status: 404 })
})
// Error handler
app.use((err, req, res, _next) => {
- // Set locals, only providing error in development
- res.locals.message = err.message
- res.locals.error = req.app.get('env') === 'development' ? err : {}
+ // Set locals, only providing error in development
+ res.locals.message = err.message
+ res.locals.error = req.app.get('env') === 'development' ? err : {}
- // Render the error page
- res.status(err.status || 500)
- res.render('error')
+ // Render the error page
+ res.status(err.status || 500)
+ res.render('error')
})
/**
@@ -77,9 +77,9 @@ app.set('port', config.http.port)
*/
server.listen(config.http.port)
server.on('listening', () => {
- const addr = server.address()
- const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port
- debug('Listening on ' + bind)
+ const addr = server.address()
+ const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port
+ debug('Listening on ' + bind)
})
-module.exports = {app, io, server}
+module.exports = { app, io, server }
\ No newline at end of file