/** * CyberSim OS - Inlook Email Application */ export class InlookApp { constructor({ windowManager, eventBus, notifications, scenario, onNavigateUrl, onOpenDoc, onFileDownloaded }) { this.wm = windowManager; this.eventBus = eventBus; this.notifications = notifications; this.scenario = scenario; this.onNavigateUrl = onNavigateUrl; this.onOpenDoc = onOpenDoc; this.onFileDownloaded = onFileDownloaded; this.currentFolder = 'inbox'; this.activeEmailId = null; this.emails = JSON.parse(JSON.stringify(scenario.emails)); } getIconSvg() { return ``; } launch() { const win = this.wm.createWindow({ id: 'inlook', title: 'Inlook Mail - NexaCore Workplace', iconSvg: this.getIconSvg(), width: 860, height: 560, bodyContent: this.renderShell() }); this.bindEvents(win.bodyElement); this.selectFirstEmail(); this.eventBus.emit('APP_OPENED', { target: 'inlook' }); } renderShell() { return `
📥 Inbox 0
📤 Sent
🗑️ Trash
Select an email message to view its contents.
`; } bindEvents(container) { container.querySelectorAll('.inlook-folder-item').forEach(el => { el.addEventListener('click', () => { container.querySelectorAll('.inlook-folder-item').forEach(f => f.classList.remove('active')); el.classList.add('active'); this.currentFolder = el.dataset.folder; this.renderEmailList(); }); }); const composeBtn = container.querySelector('#inlook-compose-btn'); if (composeBtn) { composeBtn.addEventListener('click', () => { this.notifications.show({ title: 'Inlook Mail', body: 'Corporate policy restricts unassigned outgoing mail during initial shift orientation.', type: 'info' }); }); } this.renderEmailList(); } renderEmailList() { const listEl = document.getElementById('inlook-email-list'); if (!listEl) return; const filtered = this.emails.filter(e => e.folder === this.currentFolder); const unread = this.emails.filter(e => e.folder === 'inbox' && e.unread).length; const badge = document.getElementById('inlook-unread-count'); if (badge) badge.innerText = unread; if (filtered.length === 0) { listEl.innerHTML = `
No messages in ${this.currentFolder}
`; return; } listEl.innerHTML = filtered.map(email => `
${email.sender.split('(')[0]} ${email.date}
${email.subject}
${email.body.replace(/<[^>]*>?/gm, '').substring(0, 48)}...
`).join(''); listEl.querySelectorAll('.inlook-list-item').forEach(item => { item.addEventListener('click', () => { const id = item.dataset.emailId; this.openEmail(id); }); }); } selectFirstEmail() { const inboxEmails = this.emails.filter(e => e.folder === 'inbox'); if (inboxEmails.length > 0) { this.openEmail(inboxEmails[0].id); } } openEmail(id) { const email = this.emails.find(e => e.id === id); if (!email) return; this.activeEmailId = id; email.unread = false; this.renderEmailList(); this.eventBus.emit('EMAIL_OPENED', { target: id, details: { subject: email.subject, rfcSender: email.rfcSender, isThreat: !!email.isThreat } }); const readingPane = document.getElementById('inlook-reading-pane'); if (!readingPane) return; readingPane.innerHTML = `
${email.subject}
${email.sender.charAt(0)}
${email.sender}
${email.rfcSender}
${email.date}
${email.attachments && email.attachments.length > 0 ? `
Attachments (${email.attachments.length}): ${email.attachments.map(att => `
${att.name} (${att.size})
`).join('')}
` : ''}
${email.body.replace(/\n/g, '
')}
`; this.bindEmailActions(email); } bindEmailActions(email) { const inspectBtn = document.getElementById('btn-inspect-header'); if (inspectBtn) { inspectBtn.addEventListener('click', () => { this.eventBus.emit('EMAIL_INSPECTED_SENDER', { target: email.id, details: { displaySender: email.sender, rfcSender: email.rfcSender } }); const isDomainMismatch = email.rfcSender.includes('nexac0re-portal.com') || email.rfcSender.includes('apex-global-supplies.net'); alert(`--- Inlook RFC Header Inspector ---\n\nDisplay Name: ${email.sender}\nEnvelope RFC From: <${email.rfcSender}>\nAuthentication-Results: spf=pass (domain: ${email.rfcSender.split('@')[1]})\nReturn-Path: \n\n${isDomainMismatch ? '⚠️ Notice: Envelope domain differs from standard corporate (@nexacore.internal).' : '✓ Envelope domain matches internal enterprise domain.'}`); }); } const links = document.querySelectorAll('.inlook-msg-link'); links.forEach(link => { const actualUrl = link.dataset.url; const displayText = link.dataset.display || link.innerText; link.title = `Simulated Target: ${actualUrl}`; link.addEventListener('mouseenter', () => { this.eventBus.emit('EMAIL_LINK_HOVERED', { target: email.id, details: { displayText, actualUrl } }); }); link.addEventListener('click', (e) => { e.preventDefault(); this.eventBus.emit('EMAIL_LINK_CLICKED', { target: email.id, details: { displayText, actualUrl, isPhishing: actualUrl.includes('nexac0re-portal.com') } }); if (this.onNavigateUrl) { this.onNavigateUrl(actualUrl); } }); }); const attChips = document.querySelectorAll('.inlook-attachment-chip'); attChips.forEach(chip => { chip.addEventListener('click', () => { const attName = chip.dataset.attName; const attSize = chip.dataset.attSize; this.eventBus.emit('EMAIL_ATTACHMENT_OPENED', { target: email.id, details: { attachmentName: attName, attachmentSize: attSize } }); if (this.onFileDownloaded) { this.onFileDownloaded({ id: `down_${Date.now()}`, name: attName, type: 'archive', folder: 'Downloads', size: attSize, date: new Date().toISOString().split('T')[0] }); } this.notifications.show({ title: 'Download Complete', body: `File "${attName}" saved to Downloads folder.`, type: 'warning' }); }); }); const reportBtn = document.getElementById('btn-inlook-report'); if (reportBtn) { reportBtn.addEventListener('click', () => { this.openReportDialog(email); }); } const replyBtn = document.getElementById('btn-inlook-reply'); if (replyBtn) { replyBtn.addEventListener('click', () => { this.openReplyDialog(email); }); } const deleteBtn = document.getElementById('btn-inlook-delete'); if (deleteBtn) { deleteBtn.addEventListener('click', () => { email.folder = 'trash'; this.renderEmailList(); this.eventBus.emit('EMAIL_DELETED', { target: email.id, details: { subject: email.subject, wasThreat: !!email.isThreat } }); this.selectFirstEmail(); this.notifications.show({ title: 'Inlook Mail', body: 'Message moved to Trash.', type: 'info' }); }); } } openReportDialog(email) { const modalOverlay = document.createElement('div'); modalOverlay.className = 'cs-modal-overlay'; modalOverlay.innerHTML = `
Report Suspicious Message to SOC

You are about to report the following email to the NexaCore Security Operations Center:

Subject: ${email.subject}
Sender: ${email.rfcSender}
`; document.body.appendChild(modalOverlay); const close = () => modalOverlay.remove(); modalOverlay.querySelector('#btn-close-modal').addEventListener('click', close); modalOverlay.querySelector('#btn-cancel-report').addEventListener('click', close); modalOverlay.querySelector('#btn-submit-report').addEventListener('click', () => { const reason = modalOverlay.querySelector('#report-reason').value; const notes = modalOverlay.querySelector('#report-notes').value; this.eventBus.emit('EMAIL_REPORTED', { target: email.id, details: { reason, notes, isThreat: !!email.isThreat, threatId: email.threatId || null } }); email.folder = 'trash'; this.renderEmailList(); this.selectFirstEmail(); close(); this.notifications.show({ title: 'Security Center Report Acknowledged', body: `Incident report for "${email.subject.substring(0, 30)}..." received by SOC.`, type: 'success' }); }); } openReplyDialog(email) { const modalOverlay = document.createElement('div'); modalOverlay.className = 'cs-modal-overlay'; modalOverlay.innerHTML = `
Reply to: ${email.sender}
`; document.body.appendChild(modalOverlay); const close = () => modalOverlay.remove(); modalOverlay.querySelector('#btn-close-reply').addEventListener('click', close); modalOverlay.querySelector('#btn-cancel-reply').addEventListener('click', close); modalOverlay.querySelector('#btn-send-reply').addEventListener('click', () => { const text = modalOverlay.querySelector('#reply-text').value; this.eventBus.emit('EMAIL_REPLIED', { target: email.id, details: { responseText: text, recipient: email.rfcSender } }); close(); this.notifications.show({ title: 'Inlook Mail', body: `Reply sent to ${email.sender.split('(')[0]}.`, type: 'success' }); }); } }