Korjaa HTML-renderöinti viesteissä + mailbox-valinta Zammad-tiketeille
1. Sähköpostiviestien HTML renderöidään oikein (br, p, div, a, b, i jne.) sen sijaan että tagit näkyisivät raakatekstinä. Sanitoi vaarallisen sisällön (script, iframe, on*-attribuutit) pois turvallisesti. 2. Zammad-tiketeillä ei ole mailbox_id:tä, joten aiemmin valittiin aina listan ensimmäinen (tuki@serverihuone.com). Nyt näytetään "Valitse lähettäjä" placeholder kunnes käyttäjä valitsee oikean. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Noxus HUB</title>
|
<title>Noxus HUB</title>
|
||||||
<link rel="stylesheet" href="style.css?v=20260313">
|
<link rel="stylesheet" href="style.css?v=20260313b">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Login -->
|
<!-- Login -->
|
||||||
@@ -2229,6 +2229,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="script.js?v=20260313"></script>
|
<script src="script.js?v=20260313b"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
30
script.js
30
script.js
@@ -528,6 +528,28 @@ function contractRemaining(sopimuskausi, alkupvm) {
|
|||||||
})();
|
})();
|
||||||
function esc(str) { if (!str) return ''; const d = document.createElement('div'); d.textContent = str; return d.innerHTML; }
|
function esc(str) { if (!str) return ''; const d = document.createElement('div'); d.textContent = str; return d.innerHTML; }
|
||||||
|
|
||||||
|
function sanitizeHtml(str) {
|
||||||
|
if (!str) return '';
|
||||||
|
// Salli turvalliset tagit, poista kaikki muut
|
||||||
|
const allowed = ['br', 'p', 'div', 'a', 'b', 'i', 'strong', 'em', 'ul', 'ol', 'li', 'blockquote', 'h1', 'h2', 'h3', 'h4', 'span', 'table', 'tr', 'td', 'th', 'thead', 'tbody'];
|
||||||
|
const tmp = document.createElement('div');
|
||||||
|
tmp.innerHTML = str;
|
||||||
|
// Poista script, style, iframe, object, embed, form tagit kokonaan
|
||||||
|
tmp.querySelectorAll('script,style,iframe,object,embed,form,input,textarea,button,link,meta').forEach(el => el.remove());
|
||||||
|
// Poista on*-attribuutit kaikista elementeistä
|
||||||
|
tmp.querySelectorAll('*').forEach(el => {
|
||||||
|
[...el.attributes].forEach(attr => {
|
||||||
|
if (attr.name.startsWith('on') || attr.name === 'srcdoc') el.removeAttribute(attr.name);
|
||||||
|
});
|
||||||
|
// Sanitoi href — vain http/https/mailto
|
||||||
|
if (el.hasAttribute('href')) {
|
||||||
|
const href = el.getAttribute('href') || '';
|
||||||
|
if (!/^(https?:|mailto:)/i.test(href)) el.removeAttribute('href');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return tmp.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
function timeAgo(dateStr) {
|
function timeAgo(dateStr) {
|
||||||
if (!dateStr) return '';
|
if (!dateStr) return '';
|
||||||
const date = new Date(dateStr.replace(' ', 'T'));
|
const date = new Date(dateStr.replace(' ', 'T'));
|
||||||
@@ -1800,7 +1822,7 @@ async function showTicketDetail(id, companyId = '') {
|
|||||||
<strong>${esc(m.from_name || m.from)}</strong>
|
<strong>${esc(m.from_name || m.from)}</strong>
|
||||||
<span class="ticket-msg-time">${esc(m.timestamp)}</span>
|
<span class="ticket-msg-time">${esc(m.timestamp)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="ticket-msg-body">${esc(m.body)}</div>
|
<div class="ticket-msg-body">${m.type === 'email_in' || m.type === 'incoming' || m.type === 'outgoing' ? sanitizeHtml(m.body) : esc(m.body).replace(/\n/g, '<br>')}</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
|
|
||||||
@@ -1835,9 +1857,13 @@ async function showTicketDetail(id, companyId = '') {
|
|||||||
(!currentHiddenMailboxes.includes(String(mb.id)) && !currentHiddenMailboxes.includes(mb.id))
|
(!currentHiddenMailboxes.includes(String(mb.id)) && !currentHiddenMailboxes.includes(mb.id))
|
||||||
);
|
);
|
||||||
const ticketMbId = String(ticket.mailbox_id || '');
|
const ticketMbId = String(ticket.mailbox_id || '');
|
||||||
mbSelect.innerHTML = visibleMailboxes.map(mb =>
|
const hasMatch = ticketMbId && visibleMailboxes.some(mb => String(mb.id) === ticketMbId);
|
||||||
|
let optionsHtml = '';
|
||||||
|
if (!hasMatch) optionsHtml = '<option value="" selected>— Valitse lähettäjä —</option>';
|
||||||
|
optionsHtml += visibleMailboxes.map(mb =>
|
||||||
`<option value="${esc(mb.id)}" ${String(mb.id) === ticketMbId ? 'selected' : ''}>${esc(mb.nimi || mb.smtp_from_email)} <${esc(mb.smtp_from_email)}></option>`
|
`<option value="${esc(mb.id)}" ${String(mb.id) === ticketMbId ? 'selected' : ''}>${esc(mb.nimi || mb.smtp_from_email)} <${esc(mb.smtp_from_email)}></option>`
|
||||||
).join('');
|
).join('');
|
||||||
|
mbSelect.innerHTML = optionsHtml;
|
||||||
// Vaihda allekirjoitusta kun mailbox vaihtuu
|
// Vaihda allekirjoitusta kun mailbox vaihtuu
|
||||||
mbSelect.addEventListener('change', function() {
|
mbSelect.addEventListener('change', function() {
|
||||||
updateSignaturePreview(this.value);
|
updateSignaturePreview(this.value);
|
||||||
|
|||||||
Reference in New Issue
Block a user