[Chore]: Final Cleanup
BIN
.github/assets/account.png
vendored
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
.github/assets/home.png
vendored
Normal file
|
After Width: | Height: | Size: 346 KiB |
BIN
.github/assets/inbox.png
vendored
|
Before Width: | Height: | Size: 266 KiB After Width: | Height: | Size: 241 KiB |
BIN
.github/assets/keys.png
vendored
|
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 281 KiB |
BIN
.github/assets/raw.png
vendored
|
Before Width: | Height: | Size: 265 KiB |
15
README.md
|
|
@ -33,7 +33,7 @@ All data is being removed 48hrs after they have reached the mail server.
|
|||
- Delete your emails ahead of time by pressing the delete button
|
||||
- View the raw email, showing all the headers etc.
|
||||
- Download Attachments with one click
|
||||
- Password-protected inboxes
|
||||
- <u>Optional</u> User Account System with email forwarding and inbox locking
|
||||
- and more...
|
||||
|
||||
<br>
|
||||
|
|
@ -42,13 +42,14 @@ All data is being removed 48hrs after they have reached the mail server.
|
|||
|
||||
## Screenshots
|
||||
|
||||
| Inbox | Email using HTML and CSS |
|
||||
| Homepage | Account Panel |
|
||||
|:---:|:---:|
|
||||
| <img src=".github/assets/inbox.png" width="500px" height="300px" style="object-fit: cover;"> | <img src=".github/assets/html.png" width="500px" height="300px" style="object-fit: cover;"> |
|
||||
| <img src=".github/assets/home.png" width="500px" height="300px" style="object-fit: fit;"> | <img src=".github/assets/account.png" width="500px" height="300px" style="object-fit: fit;"> |
|
||||
|
||||
| Inbox | Email using HTML and CSS | Attachments and Cryptographic Keys view |
|
||||
|:---:|:---:|:---:|
|
||||
| <img src=".github/assets/inbox.png" width="500px" height="300px" style="object-fit: fit;"> | <img src=".github/assets/html.png" width="500px" height="300px" style="object-fit: fit;"> | <img src=".github/assets/keys.png" width="500px" height="300px" style="object-fit: fit;"> |
|
||||
|
||||
| Email without CSS | Dropdown for cryptographic Keys and Signatures |
|
||||
|:---:|:---:|
|
||||
| <img src=".github/assets/raw.png" width="500px" height="300px" style="object-fit: cover;"> | <img src=".github/assets/keys.png" width="500px" height="300px" style="object-fit: cover;"> |
|
||||
|
||||
<br>
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ All data is being removed 48hrs after they have reached the mail server.
|
|||
## How can I set this up myself?
|
||||
|
||||
**Prerequisites:**
|
||||
- Mail server with IMAP (Optionally also SMTP for email forwarding feature)
|
||||
- Mail server with IMAP (Optionally also SMTP for registration and protected features)
|
||||
- One or multiple domains dedicated to this
|
||||
- git & nodejs
|
||||
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ router.get('/auth', redirectIfAuthenticated, (req, res) => {
|
|||
delete req.session.errorMessage
|
||||
delete req.session.successMessage
|
||||
|
||||
res.render('login-auth', {
|
||||
res.render('auth', {
|
||||
title: `Login or Register | ${config.http.branding[0]}`,
|
||||
branding: config.http.branding,
|
||||
errorMessage,
|
||||
|
|
|
|||
|
|
@ -658,8 +658,9 @@ router.get('/verify', async(req, res, next) => {
|
|||
|
||||
debug(`Email ${destinationEmail} verified successfully, cookie set for 24 hours`)
|
||||
|
||||
// Redirect to success page
|
||||
return res.redirect(`/inbox/verify-success?email=${encodeURIComponent(destinationEmail)}`)
|
||||
// Show success on account page
|
||||
req.session.accountSuccess = `Successfully verified ${destinationEmail}!`
|
||||
return res.redirect('/account')
|
||||
} catch (error) {
|
||||
debug(`Error during verification: ${error.message}`)
|
||||
console.error('Error during email verification', error)
|
||||
|
|
@ -667,29 +668,4 @@ router.get('/verify', async(req, res, next) => {
|
|||
res.redirect('/')
|
||||
}
|
||||
})
|
||||
|
||||
// GET route for verification success page
|
||||
router.get('/verify-success', async(req, res) => {
|
||||
const { email } = req.query
|
||||
|
||||
if (!email) {
|
||||
return res.redirect('/')
|
||||
}
|
||||
|
||||
const config = req.app.get('config')
|
||||
const mailProcessingService = req.app.get('mailProcessingService')
|
||||
const count = await mailProcessingService.getCount()
|
||||
const largestUid = await req.app.locals.imapService.getLargestUid()
|
||||
const totalcount = helper.countElementBuilder(count, largestUid)
|
||||
|
||||
res.render('verify-success', {
|
||||
title: `Email Verified | ${config.http.branding[0]}`,
|
||||
email: email,
|
||||
branding: config.http.branding,
|
||||
purgeTime: purgeTime,
|
||||
totalcount: totalcount
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
module.exports = router
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@
|
|||
{% endif %}
|
||||
{% if verificationSent %}
|
||||
<div class="verification-message">
|
||||
📧 Verification email sent to <strong>{{ verificationEmail }}</strong>. Please check your inbox and click the verification link (expires in 15 minutes).
|
||||
Verification email sent to <strong>{{ verificationEmail }}</strong>. Please check your inbox and click the verification link (expires in 15 minutes).
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if errorMessage %}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
{% endif %}
|
||||
{% if verificationSent %}
|
||||
<div class="verification-message">
|
||||
📧 Verification email sent to <strong>{{ verificationEmail }}</strong>. Please check your inbox and click the verification link (expires in 15 minutes).
|
||||
Verification email sent to <strong>{{ verificationEmail }}</strong>. Please check your inbox and click the verification link (expires in 15 minutes).
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="mail-container">
|
||||
|
|
|
|||
|
|
@ -1,96 +0,0 @@
|
|||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block header %}
|
||||
<div class="action-links">
|
||||
<a href="/" aria-label="Return to home">← Home</a>
|
||||
<a href="/login" aria-label="Login">Login</a>
|
||||
<button class="theme-toggle" id="themeToggle" aria-label="Toggle dark/light mode">
|
||||
<svg class="theme-icon theme-icon-dark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
<svg class="theme-icon theme-icon-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div id="register" class="auth-container">
|
||||
<div class="auth-card">
|
||||
<h1>Create Account</h1>
|
||||
<p class="auth-subtitle">Sign up to unlock email forwarding and inbox locking</p>
|
||||
|
||||
{% if errorMessage %}
|
||||
<div class="unlock-error">
|
||||
{{ errorMessage }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if successMessage %}
|
||||
<div class="success-message">
|
||||
{{ successMessage }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="POST" action="/register">
|
||||
<fieldset>
|
||||
<label for="username">Username</label>
|
||||
<input
|
||||
type="text"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="3-20 characters, alphanumeric and underscore"
|
||||
required
|
||||
minlength="3"
|
||||
maxlength="20"
|
||||
pattern="[a-zA-Z0-9_]+"
|
||||
autocomplete="username"
|
||||
>
|
||||
<small>Only letters, numbers, and underscores allowed</small>
|
||||
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Min 8 characters"
|
||||
required
|
||||
minlength="8"
|
||||
autocomplete="new-password"
|
||||
>
|
||||
<small>Must contain uppercase, lowercase, and number</small>
|
||||
|
||||
<label for="confirmPassword">Confirm Password</label>
|
||||
<input
|
||||
type="password"
|
||||
id="confirmPassword"
|
||||
name="confirmPassword"
|
||||
placeholder="Re-enter your password"
|
||||
required
|
||||
minlength="8"
|
||||
autocomplete="new-password"
|
||||
>
|
||||
|
||||
<div class="auth-actions">
|
||||
<button class="button button-primary" type="submit">Create Account</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>Already have an account? <a href="/login">Login here</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="auth-features">
|
||||
<h3>Why Register?</h3>
|
||||
<ul>
|
||||
<li>✓ Forward emails to your real address</li>
|
||||
<li>✓ Lock up to 5 inboxes with passwords</li>
|
||||
<li>✓ Manage multiple verified forwarding emails</li>
|
||||
<li>✓ Access your locked inboxes from anywhere</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
{% extends 'layout.twig' %}
|
||||
|
||||
{% block header %}
|
||||
<div class="action-links">
|
||||
{% if currentUser %}
|
||||
<!-- Account Dropdown (logged in) -->
|
||||
{% if authEnabled %}
|
||||
<div class="action-dropdown">
|
||||
<button class="dropdown-toggle" aria-label="Account menu">Account ▾</button>
|
||||
<div class="dropdown-menu">
|
||||
<a href="/account" aria-label="Account settings">Settings</a>
|
||||
<a href="/logout?redirect=/" aria-label="Logout">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if authEnabled %}
|
||||
<a href="/auth" aria-label="Login or Register">Account</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<a href="/" aria-label="Return to home">Home</a>
|
||||
<button class="theme-toggle" id="themeToggle" aria-label="Toggle dark/light mode">
|
||||
<svg class="theme-icon theme-icon-dark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
<svg class="theme-icon theme-icon-light" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="verification-success-container">
|
||||
<div class="verification-success-card">
|
||||
<div class="verification-success-icon">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path>
|
||||
<polyline points="22 4 12 14.01 9 11.01"></polyline>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1>Email Verified Successfully!</h1>
|
||||
|
||||
<div class="verification-details">
|
||||
<p>You have verified ownership of:</p>
|
||||
<p class="verified-email">{{ email }}</p>
|
||||
</div>
|
||||
|
||||
<div class="verification-info">
|
||||
<p>✓ You can now forward emails to this address for the next <strong>24 hours</strong></p>
|
||||
<p>✓ After 24 hours, you'll need to verify again</p>
|
||||
<p>✓ You can close this tab and return to your inbox</p>
|
||||
</div>
|
||||
|
||||
<div class="verification-actions">
|
||||
<a href="/" class="button button-primary">Return to {{ branding[0] }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "48hr.email",
|
||||
"version": "1.8.2",
|
||||
"version": "1.9.0",
|
||||
"private": false,
|
||||
"description": "48hr.email is your favorite open-source tempmail client.",
|
||||
"keywords": [
|
||||
|
|
|
|||