48hr.email/api/routes/inbox.js
2026-01-05 12:51:15 +01:00

141 lines
No EOL
4.4 KiB
JavaScript

const express = require('express')
const router = express.Router()
const createAuthenticator = require('../middleware/authenticator')
/**
* Inbox & Mail Retrieval API Routes
* GET /:address - List emails in inbox
* GET /:address/:uid - Get full email by UID
* GET /:address/:uid/raw - Get raw email source
* GET /:address/:uid/attachment/:checksum - Download attachment
*/
function createInboxRouter(dependencies) {
const { mailProcessingService, apiTokenRepository } = dependencies
const { optionalAuth } = createAuthenticator(apiTokenRepository)
/**
* GET /:address - List mail summaries for an inbox
*/
router.get('/:address', optionalAuth, async(req, res, next) => {
try {
const address = req.params.address.toLowerCase()
// Get mail summaries
const mails = mailProcessingService.getMailSummaries(address)
res.apiList(mails)
} catch (error) {
next(error)
}
})
/**
* GET /:address/:uid - Get full email by UID
*/
router.get('/:address/:uid', optionalAuth, async(req, res, next) => {
try {
const address = req.params.address.toLowerCase()
const uid = parseInt(req.params.uid)
if (isNaN(uid)) {
return res.apiError('Invalid UID', 'VALIDATION_ERROR', 400)
}
// Get full email
const mail = await mailProcessingService.getOneFullMail(address, uid, false)
if (!mail) {
return res.apiError('Email not found', 'NOT_FOUND', 404)
}
// Format response
const response = {
uid: uid,
to: mail.to,
from: mail.from,
date: mail.date,
subject: mail.subject,
text: mail.text,
html: mail.html,
attachments: mail.attachments ? mail.attachments.map(att => ({
filename: att.filename,
contentType: att.contentType,
size: att.content ? att.content.length : 0,
checksum: att.checksum
})) : []
}
res.apiSuccess(response)
} catch (error) {
next(error)
}
})
/**
* GET /:address/:uid/raw - Get raw email source
*/
router.get('/:address/:uid/raw', optionalAuth, async(req, res, next) => {
try {
const address = req.params.address.toLowerCase()
const uid = parseInt(req.params.uid)
if (isNaN(uid)) {
return res.apiError('Invalid UID', 'VALIDATION_ERROR', 400)
}
// Get raw email
const rawMail = await mailProcessingService.getOneFullMail(address, uid, true)
if (!rawMail) {
return res.apiError('Email not found', 'NOT_FOUND', 404)
}
// Return as plain text
res.setHeader('Content-Type', 'text/plain')
res.send(rawMail)
} catch (error) {
next(error)
}
})
/**
* GET /:address/:uid/attachment/:checksum - Download attachment
*/
router.get('/:address/:uid/attachment/:checksum', optionalAuth, async(req, res, next) => {
try {
const address = req.params.address.toLowerCase()
const uid = parseInt(req.params.uid)
const checksum = req.params.checksum
if (isNaN(uid)) {
return res.apiError('Invalid UID', 'VALIDATION_ERROR', 400)
}
// Get full email to access attachments
const mail = await mailProcessingService.getOneFullMail(address, uid, false)
if (!mail || !mail.attachments) {
return res.apiError('Email or attachment not found', 'NOT_FOUND', 404)
}
// Find attachment by checksum
const attachment = mail.attachments.find(att => att.checksum === checksum)
if (!attachment) {
return res.apiError('Attachment not found', 'NOT_FOUND', 404)
}
// Send attachment
res.setHeader('Content-Type', attachment.contentType || 'application/octet-stream')
res.setHeader('Content-Disposition', `attachment; filename="${attachment.filename}"`)
res.send(attachment.content)
} catch (error) {
next(error)
}
})
return router
}
module.exports = createInboxRouter