From 5b86d31cfd9e5af35d4855ae905aca7d24f9b8a3 Mon Sep 17 00:00:00 2001 From: brandon Date: Fri, 6 Jun 2025 19:59:02 -0700 Subject: [PATCH] initial commit --- inbox.html | 19 ++++++ index.html | 19 ++++++ login.html | 22 +++++++ main.js | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++ register.html | 22 +++++++ send.html | 23 +++++++ style.css | 64 ++++++++++++++++++ 7 files changed, 345 insertions(+) create mode 100644 inbox.html create mode 100644 index.html create mode 100644 login.html create mode 100644 main.js create mode 100644 register.html create mode 100644 send.html create mode 100644 style.css diff --git a/inbox.html b/inbox.html new file mode 100644 index 0000000..73413c2 --- /dev/null +++ b/inbox.html @@ -0,0 +1,19 @@ + + + + + + Inbox - Bang Webmail + + + +
+

Inbox

+ + +
+

+
+ + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..da3a2b5 --- /dev/null +++ b/index.html @@ -0,0 +1,19 @@ + + + + + + Bang Webmail + + + +
+

Bang Webmail

+ +

Welcome to Bang Webmail! Please login or register to continue.

+
+ + diff --git a/login.html b/login.html new file mode 100644 index 0000000..8e4f1ff --- /dev/null +++ b/login.html @@ -0,0 +1,22 @@ + + + + + + Login - Bang Webmail + + + +
+

Login

+
+
+
+ +
+

+ Don't have an account? Register +
+ + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..95bfbb7 --- /dev/null +++ b/main.js @@ -0,0 +1,176 @@ +// Utility: Save and load credentials +function saveCredentials(username, password) { + localStorage.setItem('username', username); + localStorage.setItem('password', password); +} +function getCredentials() { + return { + username: localStorage.getItem('username'), + password: localStorage.getItem('password') + }; +} +function clearCredentials() { + localStorage.removeItem('username'); + localStorage.removeItem('password'); +} +function logout() { + clearCredentials(); + window.location.href = 'login.html'; +} + +// Registration +if (document.getElementById('registerForm')) { + document.getElementById('registerForm').onsubmit = async function(e) { + e.preventDefault(); + const username = document.getElementById('registerUsername').value; + const password = document.getElementById('registerPassword').value; + const res = await fetch('http://localhost:8080/users', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ username, password }) + }); + if (res.ok) { + saveCredentials(username, password); + window.location.href = 'inbox.html'; + } else { + const err = await res.text(); + document.getElementById('registerError').innerText = err; + } + }; +} + +// Login +if (document.getElementById('loginForm')) { + document.getElementById('loginForm').onsubmit = async function(e) { + e.preventDefault(); + const username = document.getElementById('loginUsername').value; + const password = document.getElementById('loginPassword').value; + // Try to fetch mailbox to verify credentials + const res = await fetch(`http://localhost:8080/mailbox?user=${encodeURIComponent(username)}`, { + headers: { 'Authorization': 'Basic ' + btoa(username + ':' + password) } + }); + if (res.ok) { + saveCredentials(username, password); + window.location.href = 'inbox.html'; + } else { + document.getElementById('loginError').innerText = 'Invalid username or password.'; + } + }; +} + +// Inbox +if (document.getElementById('inboxList')) { + const { username, password } = getCredentials(); + if (!username || !password) { + window.location.href = 'login.html'; + } else { + fetch(`http://localhost:8080/mailbox?user=${encodeURIComponent(username)}`, { + headers: { 'Authorization': 'Basic ' + btoa(username + ':' + password) } + }) + .then(res => res.json()) + .then(emails => { + if (!Array.isArray(emails)) throw new Error('Invalid mailbox response'); + // Determine current user's full address (username!domain if possible) + // Try to find domain from any received or sent email + let userDomain = null; + for (const email of emails) { + if (email.to === username && email.domain) { + userDomain = email.domain; + break; + } + if (email.from === username && email.domain) { + userDomain = email.domain; + break; + } + } + const userFull = userDomain ? `${username}!${userDomain}` : username; + // Inbox: emails where 'to!domain' matches current user + const inboxEmails = emails.filter(email => { + if (!email.to) return false; + const toFull = email.domain ? `${email.to}!${email.domain}` : email.to; + return toFull === userFull; + }); + // Sent: emails where 'from!domain' matches current user + const sentEmails = emails.filter(email => { + if (!email.from) return false; + const fromFull = email.domain ? `${email.from}!${email.domain}` : email.from; + return fromFull === userFull; + }); + let html = ''; + html += '

Inbox

'; + if (inboxEmails.length === 0) { + html += '

No emails.

'; + } else { + html += inboxEmails.map(email => { + const fromDisplay = email.domain ? `${email.from}!${email.domain}` : email.from; + return ` +
+ From: ${fromDisplay}
+ Subject: ${email.subject}
+
${email.body}
+
+ `; + }).join(''); + } + html += '

Sent

'; + if (sentEmails.length === 0) { + html += '

No sent emails.

'; + } else { + html += sentEmails.map(email => { + const toDisplay = email.domain ? `${email.to}!${email.domain}` : email.to; + return ` +
+ To: ${toDisplay}
+ Subject: ${email.subject}
+
${email.body}
+
+ `; + }).join(''); + } + document.getElementById('inboxList').innerHTML = html; + }) + .catch(err => { + document.getElementById('inboxError').innerText = 'Failed to load inbox.'; + }); + } +} + +// Send Email +if (document.getElementById('sendForm')) { + document.getElementById('sendForm').onsubmit = async function(e) { + e.preventDefault(); + const { username, password } = getCredentials(); + if (!username || !password) { + window.location.href = 'login.html'; + return; + } + const toField = document.getElementById('to').value.trim(); + // Require ! format + if (!/^\w+!.+/.test(toField)) { + document.getElementById('sendError').innerText = 'Recipient must be in the format username!domain'; + return; + } + let to = toField; + let domain = ''; + if (toField.includes('!')) { + [to, domain] = toField.split('!'); + } + const subject = document.getElementById('subject').value; + const body = document.getElementById('body').value; + const email = domain ? { from: username, to, domain, subject, body } : { from: username, to, subject, body }; + const res = await fetch('http://localhost:8080/email', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Basic ' + btoa(username + ':' + password) + }, + body: JSON.stringify(email) + }); + if (res.ok) { + window.location.href = 'inbox.html'; + } else { + const err = await res.text(); + document.getElementById('sendError').innerText = err; + } + }; +} diff --git a/register.html b/register.html new file mode 100644 index 0000000..1bc01c8 --- /dev/null +++ b/register.html @@ -0,0 +1,22 @@ + + + + + + Register - Bang Webmail + + + +
+

Register

+
+
+
+ +
+

+ Already have an account? Login +
+ + + diff --git a/send.html b/send.html new file mode 100644 index 0000000..8a39d5f --- /dev/null +++ b/send.html @@ -0,0 +1,23 @@ + + + + + + Send Email - Bang Webmail + + + +
+

Compose Email

+
+
+
+
+ +
+

+ +
+ + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..fd91b7b --- /dev/null +++ b/style.css @@ -0,0 +1,64 @@ +body { + font-family: Arial, sans-serif; + background: #f4f4f4; + margin: 0; + padding: 0; +} +.container { + background: #fff; + max-width: 400px; + margin: 40px auto; + padding: 30px 40px; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} +h1, h2 { + text-align: center; +} +nav { + text-align: center; + margin-bottom: 20px; +} +nav a { + margin: 0 10px; + color: #0077cc; + text-decoration: none; +} +nav a:hover { + text-decoration: underline; +} +input, textarea, button { + width: 100%; + margin: 8px 0; + padding: 10px; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; +} +button { + background: #0077cc; + color: #fff; + border: none; + cursor: pointer; + font-weight: bold; +} +button:hover { + background: #005fa3; +} +.error { + color: #d8000c; + text-align: center; +} +#inboxList { + margin-top: 20px; +} +.email-item { + border-bottom: 1px solid #eee; + padding: 10px 0; +} +.email-item:last-child { + border-bottom: none; +} +.email-item strong { + color: #0077cc; +}