Refactor email purge time configuration and usage to be more precise.
- New purgeTIme now allows to configure a purge to be every X minutes, hours or days. - Also remove a bit more trust by pulling footer deletion time from config. - TODO: implement 'convertUp' function, converting numbers up to the biggest possible value where `i > 2 (so 48hrs still works as per slogan and domain)`. I.e. 72hrs = 3 days, 360minutes = 6hrs, 1440minutes to 24hrs Co-authored-by: Johannes Bülow <kontakt@jmbit.de>pull/16/head
parent
d66d76c9f9
commit
71fd513bc0
|
@ -1,7 +1,11 @@
|
||||||
const config = {
|
const config = {
|
||||||
email: {
|
email: {
|
||||||
domains: process.env.EMAIL_DOMAINS,
|
domains: process.env.EMAIL_DOMAINS,
|
||||||
deleteMailsOlderThanDays: process.env.EMAIL_DELETE_MAILS_OLDER_THAN_DAYS || 2
|
purgeTime: process.env.PURGE_TIME || {
|
||||||
|
time: 48,
|
||||||
|
unit: 'hours', // minutes, hours, days
|
||||||
|
convert: true, // Convert to highest sensible unit
|
||||||
|
}
|
||||||
},
|
},
|
||||||
imap: {
|
imap: {
|
||||||
user: process.env.IMAP_USER,
|
user: process.env.IMAP_USER,
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
const config = require('./config')
|
||||||
|
const moment = require('moment')
|
||||||
|
|
||||||
|
class Helper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize our config into a proper timestamp, so we know what emails to purge
|
||||||
|
* @returns {Date}
|
||||||
|
*/
|
||||||
|
purgeTimeStamp() {
|
||||||
|
return moment()
|
||||||
|
.subtract(config.email.purgeTime.time, config.email.purgeTime.unit)
|
||||||
|
.toDate()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if time difference between now and purgeTimeStamp is more than one day
|
||||||
|
* @param {Date} now
|
||||||
|
* @param {Date} past
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
moreThanOneDay(now, past) {
|
||||||
|
const DAY_IN_MS = 24 * 60 * 60 * 1000;
|
||||||
|
if((now - past) / DAY_IN_MS >= 1){
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert time to highest possible unit where i > 2
|
||||||
|
* @returns {Date}
|
||||||
|
*/
|
||||||
|
convertUp(time, unit) {
|
||||||
|
// TODO: Implement
|
||||||
|
return time +` ${unit}`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Helper
|
|
@ -8,7 +8,8 @@ const debug = require('debug')('48hr-email:imap')
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const Mail = require('../domain/mail')
|
const Mail = require('../domain/mail')
|
||||||
|
const Helper = require('./helper')
|
||||||
|
const helper = new(Helper)
|
||||||
|
|
||||||
// Just adding some missing functions to imap-simple... :-)
|
// Just adding some missing functions to imap-simple... :-)
|
||||||
|
|
||||||
|
@ -199,22 +200,30 @@ class ImapService extends EventEmitter {
|
||||||
* @param {Date} deleteMailsBefore delete mails before this date instance
|
* @param {Date} deleteMailsBefore delete mails before this date instance
|
||||||
*/
|
*/
|
||||||
async deleteOldMails(deleteMailsBefore) {
|
async deleteOldMails(deleteMailsBefore) {
|
||||||
let uids = await this._searchWithoutFetch([
|
let uids = []
|
||||||
['!DELETED'],
|
if (helper.moreThanOneDay(moment(), deleteMailsBefore)) {
|
||||||
['BEFORE', deleteMailsBefore]
|
//fetch mails from date -1day (calculated in MS) to avoid wasting resources
|
||||||
])
|
deleteMailsBefore = deleteMailsBefore - 24 * 60 * 60 * 1000
|
||||||
|
uids = await this._searchWithoutFetch([
|
||||||
|
['!DELETED'],
|
||||||
|
['BEFORE', deleteMailsBefore]
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
uids = await this._searchWithoutFetch([
|
||||||
|
['!DELETED']
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
if (uids.length === 0) {
|
if (uids.length === 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeleteOlderThan = moment()
|
const DeleteOlderThan = helper.purgeTimeStamp()
|
||||||
.subtract(this.config.email.deleteMailsOlderThanDays, 'days')
|
|
||||||
.toDate()
|
|
||||||
|
|
||||||
const uidsWithHeaders = await this._getMailHeaders(uids)
|
const uidsWithHeaders = await this._getMailHeaders(uids)
|
||||||
uidsWithHeaders.forEach(mail => {
|
uidsWithHeaders.forEach(mail => {
|
||||||
if (mail['attributes'].date > DeleteOlderThan || this.config.http.examples.uids.includes(parseInt(mail['attributes'].id))) {
|
if (mail['attributes'].date > DeleteOlderThan || this.config.http.examples.uids.includes(parseInt(mail['attributes'].id))) {
|
||||||
uids.filter(uid => uid !== mail['attributes'].uid)
|
uids = uids.filter(uid => uid !== mail['attributes'].uid)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,9 @@ const debug = require('debug')('48hr-email:imap-manager')
|
||||||
const mem = require('mem')
|
const mem = require('mem')
|
||||||
const moment = require('moment')
|
const moment = require('moment')
|
||||||
const ImapService = require('./imap-service')
|
const ImapService = require('./imap-service')
|
||||||
|
const Helper = require('./helper')
|
||||||
|
const helper = new(Helper)
|
||||||
|
|
||||||
|
|
||||||
class MailProcessingService extends EventEmitter {
|
class MailProcessingService extends EventEmitter {
|
||||||
constructor(mailRepository, imapService, clientNotification, config) {
|
constructor(mailRepository, imapService, clientNotification, config) {
|
||||||
|
@ -71,15 +74,7 @@ class MailProcessingService extends EventEmitter {
|
||||||
|
|
||||||
async _deleteOldMails() {
|
async _deleteOldMails() {
|
||||||
try {
|
try {
|
||||||
await this.imapService.deleteOldMails(
|
await this.imapService.deleteOldMails(helper.purgeTimeStamp())
|
||||||
moment()
|
|
||||||
// Because of how we have to handle the times (IMAP isnt time-aware), we need to subtract one day
|
|
||||||
// to get all mails in their last few hours before technical purge
|
|
||||||
//
|
|
||||||
// This is a bit of a hack, but it works. See imap-service.js#deleteOldMails (L211-227) for more info
|
|
||||||
.subtract(this.config.email.deleteMailsOlderThanDays - 1, 'days')
|
|
||||||
.toDate()
|
|
||||||
)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('can not delete old messages', error)
|
console.log('can not delete old messages', error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,12 @@ const express = require('express')
|
||||||
const router = new express.Router()
|
const router = new express.Router()
|
||||||
const {param} = require('express-validator')
|
const {param} = require('express-validator')
|
||||||
const config = require('../../../application/config')
|
const config = require('../../../application/config')
|
||||||
|
const Helper = require('../../../application/helper')
|
||||||
|
const helper = new(Helper)
|
||||||
|
|
||||||
|
const purgeTime = config.email.purgeTime.convert ? helper.convertUp(config.email.purgeTime.time, config.email.purgeTime.unit)
|
||||||
|
: config.email.purgeTime.time +` ${config.email.purgeTime.unit}`;
|
||||||
|
|
||||||
const sanitizeAddress = param('address').customSanitizer(
|
const sanitizeAddress = param('address').customSanitizer(
|
||||||
(value, {req}) => {
|
(value, {req}) => {
|
||||||
return req.params.address
|
return req.params.address
|
||||||
|
@ -15,6 +21,7 @@ router.get('^/:address([^@/]+@[^@/]+)', sanitizeAddress, (req, res, _next) => {
|
||||||
const mailProcessingService = req.app.get('mailProcessingService')
|
const mailProcessingService = req.app.get('mailProcessingService')
|
||||||
res.render('inbox', {
|
res.render('inbox', {
|
||||||
title: `${config.http.branding[0]} | ` + req.params.address,
|
title: `${config.http.branding[0]} | ` + req.params.address,
|
||||||
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
|
mailSummaries: mailProcessingService.getMailSummaries(req.params.address),
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
|
@ -41,6 +48,7 @@ router.get(
|
||||||
res.set('Cache-Control', 'private, max-age=600')
|
res.set('Cache-Control', 'private, max-age=600')
|
||||||
res.render('mail', {
|
res.render('mail', {
|
||||||
title: mail.subject + " | " + req.params.address,
|
title: mail.subject + " | " + req.params.address,
|
||||||
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
mail,
|
mail,
|
||||||
uid: req.params.uid,
|
uid: req.params.uid,
|
||||||
|
@ -50,6 +58,7 @@ router.get(
|
||||||
res.render(
|
res.render(
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
|
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
|
||||||
branding: config.http.branding
|
branding: config.http.branding
|
||||||
|
@ -124,6 +133,7 @@ router.get(
|
||||||
res.render(
|
res.render(
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
message: 'This attachment could not be found. It either does not exist or has been deleted from our servers!',
|
message: 'This attachment could not be found. It either does not exist or has been deleted from our servers!',
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
|
@ -163,6 +173,7 @@ router.get(
|
||||||
res.render(
|
res.render(
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
|
purgeTime: purgeTime,
|
||||||
address: req.params.address,
|
address: req.params.address,
|
||||||
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
|
message: 'This mail could not be found. It either does not exist or has been deleted from our servers!',
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
|
|
|
@ -4,11 +4,17 @@ const router = new express.Router()
|
||||||
const randomWord = require('random-word')
|
const randomWord = require('random-word')
|
||||||
const {check, validationResult} = require('express-validator')
|
const {check, validationResult} = require('express-validator')
|
||||||
const config = require('../../../application/config')
|
const config = require('../../../application/config')
|
||||||
|
const Helper = require('../../../application/helper')
|
||||||
|
const helper = new(Helper)
|
||||||
|
|
||||||
|
const purgeTime = config.email.purgeTime.convert ? helper.convertUp(config.email.purgeTime.time, config.email.purgeTime.unit)
|
||||||
|
: config.email.purgeTime.time +` ${config.email.purgeTime.unit}`;
|
||||||
|
|
||||||
router.get('/', (req, res, _next) => {
|
router.get('/', (req, res, _next) => {
|
||||||
res.render('login', {
|
res.render('login', {
|
||||||
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
||||||
username: randomWord(),
|
username: randomWord(),
|
||||||
|
purgeTime: purgeTime,
|
||||||
domains: config.email.domains,
|
domains: config.email.domains,
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
})
|
})
|
||||||
|
@ -39,6 +45,7 @@ router.post(
|
||||||
return res.render('login', {
|
return res.render('login', {
|
||||||
userInputError: true,
|
userInputError: true,
|
||||||
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
title: `${config.http.branding[0]} | Your temporary Inbox`,
|
||||||
|
purgeTime: purgeTime,
|
||||||
username: randomWord(),
|
username: randomWord(),
|
||||||
branding: config.http.branding,
|
branding: config.http.branding,
|
||||||
})
|
})
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
{% block footer %}
|
{% block footer %}
|
||||||
<section class="container footer">
|
<section class="container footer">
|
||||||
<hr>
|
<hr>
|
||||||
<h4>{{ branding[0] }} offered by <a href="{{ branding[2] }}" style="text-decoration:underline" target="_blank">{{ branding[1] }}</a> | All Emails will be deleted after 48hrs | This project is <a href="https://github.com/crazyco-xyz/48hr.email" style="text-decoration:underline" target="_blank">open-source ♥</a></h4>
|
<h4>{{ branding[0] }} offered by <a href="{{ branding[2] }}" style="text-decoration:underline" target="_blank">{{ branding[1] }}</a> | All Emails will be deleted after {{ purgeTime }} | This project is <a href="https://github.com/crazyco-xyz/48hr.email" style="text-decoration:underline" target="_blank">open-source ♥</a></h4>
|
||||||
</section>
|
</section>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue