mirror of
https://github.com/Crazyco-xyz/48hr.email.git
synced 2026-01-09 19:29:34 +01:00
{Feat]: Overhaul raw mail view
This commit is contained in:
parent
cfe5602d4a
commit
214e7d31eb
3 changed files with 108 additions and 20 deletions
|
|
@ -679,4 +679,60 @@ label {
|
|||
|
||||
.email-expiry .expiry-timer[style*="color: #b00"] {
|
||||
color: #b00 !important;
|
||||
}
|
||||
|
||||
|
||||
/* Raw mail view */
|
||||
|
||||
.raw-container {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.raw-mail {
|
||||
background: rgba(0, 0, 0, 0.35);
|
||||
color: #e0e0e0;
|
||||
padding: 20px;
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
overflow-x: auto;
|
||||
font-family: Consolas, 'Courier New', monospace;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.raw-tabs {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.raw-tab-button {
|
||||
padding: 8px 14px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
color: #e0e0e0;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.raw-tab-button.active {
|
||||
background: rgba(155, 77, 202, 0.25);
|
||||
border-color: rgba(155, 77, 202, 0.4);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.raw-tab-button:hover {
|
||||
border-color: rgba(155, 77, 202, 0.5);
|
||||
}
|
||||
|
||||
.raw-panels {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.raw-mail.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -252,13 +252,33 @@ router.get(
|
|||
true
|
||||
)
|
||||
if (mail) {
|
||||
mail = mail.replace(/(?:\r\n|\r|\n)/g, '<br>')
|
||||
// Emails are immutable, cache if found
|
||||
const decodeQuotedPrintable = (input) => {
|
||||
if (!input) return '';
|
||||
// Remove soft line breaks
|
||||
let cleaned = input.replace(/=\r?\n/g, '');
|
||||
// Decode =XX hex escapes
|
||||
cleaned = cleaned.replace(/=([0-9A-Fa-f]{2})/g, (_, hex) => {
|
||||
try {
|
||||
return String.fromCharCode(parseInt(hex, 16));
|
||||
} catch {
|
||||
return '=' + hex;
|
||||
}
|
||||
});
|
||||
return cleaned;
|
||||
};
|
||||
|
||||
const decodedMail = decodeQuotedPrintable(mail);
|
||||
|
||||
// Keep raw content but add literal newlines after <br> tags for readability
|
||||
const rawMail = mail.replace(/<br\s*\/?\s*>/gi, '<br>\n');
|
||||
|
||||
// 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', {
|
||||
title: req.params.uid + " | raw | " + req.params.address,
|
||||
mail,
|
||||
mail: rawMail,
|
||||
decoded: decodedMail,
|
||||
totalcount: totalcount
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,31 @@
|
|||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block header %}{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui">
|
||||
<meta name="darkreader-lock">
|
||||
<meta name="description" content="Dont give shady companies your real email. Use 48hr.email to protect your privacy!">
|
||||
<meta property="og:image" content="/images/logo.png">
|
||||
|
||||
<link rel="shortcut icon" href="/images/logo.ico">
|
||||
<link rel='stylesheet' href='/dependencies/milligram.css' />
|
||||
<link rel='stylesheet' href='/stylesheets/custom.css' />
|
||||
|
||||
<script src="/socket.io/socket.io.js" defer="true"></script>
|
||||
<script src="/javascripts/notifications.js" defer="true"></script>
|
||||
|
||||
</head>
|
||||
{{ mail | raw }}
|
||||
<div class="raw-container">
|
||||
<div class="raw-tabs">
|
||||
<button class="raw-tab-button active" data-target="raw">Raw (escaped)</button>
|
||||
<button class="raw-tab-button" data-target="decoded">Decoded (quoted-printable)</button>
|
||||
</div>
|
||||
<div class="raw-panels">
|
||||
<pre class="raw-mail" data-panel="raw">{{ mail | e }}</pre>
|
||||
<pre class="raw-mail hidden" data-panel="decoded">{{ decoded | e }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const buttons = document.querySelectorAll('.raw-tab-button');
|
||||
const panels = document.querySelectorAll('.raw-mail[data-panel]');
|
||||
buttons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const target = btn.dataset.target;
|
||||
buttons.forEach(b => b.classList.toggle('active', b === btn));
|
||||
panels.forEach(p => p.classList.toggle('hidden', p.dataset.panel !== target));
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block footer %}{% endblock %}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue