almost done with the rework. Just the JSON API missing

This commit is contained in:
Chris 2023-11-11 14:36:34 +01:00
parent c3af7b2afa
commit 2bfe9f297c
8 changed files with 116 additions and 8 deletions

View file

@ -33,6 +33,9 @@
- 100% file based, no database needed
- Can be used as Email Honeypot
# JSON API
## [INFO] March '23
Since Docker Hub won't allow team Organizations anymore, we moved our images to GitHub Container Registry. So if you want to use the latest version, please use the new image ghcr.io/hascheksolutions/opentrashmail instead of hascheksolutions/opentrashmail
@ -60,9 +63,9 @@ Just edit the `config.ini` You can use the following settings
- [x] Admin overview for all available email addresses
- [x] Option to show raw email
- [x] Delete messages
- [ ] Secure HTML, so no malicious things can be loaded
- [x] Make better theme
- [x] Secure HTML, so no malicious things can be loaded
- [ ] Display embedded images inline using Content-ID
- [ ] Make better theme
- [ ] Configurable settings
- [x] Choose domains for random generation
- [x] Choose if out-of-scope emails are discarded

View file

@ -20,4 +20,12 @@ tr.htmx-swapping td {
.htmx-indicator{
display:none;
}
/* pico css overrides */
:root {
--form-element-spacing-vertical: 0.15rem;
--form-element-spacing-horizontal: 1rem;
}

View file

@ -18,6 +18,12 @@ class OpenTrashmailBackend{
return $this->listAccount($_REQUEST['email']?:$this->url[2]);
case 'read':
return $this->readMail($_REQUEST['email']?:$this->url[2],$_REQUEST['id']?:$this->url[3]);
case 'listaccounts':
if($this->settings['SHOW_ACCOUNT_LIST'])
return $this->listAccounts();
else return '403 Forbidden';
case 'raw-html':
return $this->getRawMail($this->url[2],$this->url[3],true);
case 'raw':
return $this->getRawMail($this->url[2],$this->url[3]);
case 'attachment':
@ -28,6 +34,8 @@ class OpenTrashmailBackend{
$addr = generateRandomEmail();
//add header HX-Redirect
return $this->listAccount($addr);
case 'deleteaccount':
return $this->deleteAccount($_REQUEST['email']?:$this->url[2]);
default:
return false;
}
@ -51,6 +59,24 @@ class OpenTrashmailBackend{
else return false;
}
function deleteAccount($email)
{
if(!filter_var($email, FILTER_VALIDATE_EMAIL))
return $this->error('Invalid email address');
$path = getDirForEmail($email);
if(is_dir($path))
delTree($path);
}
function listAccounts()
{
$accounts = listEmailAdresses();
return $this->renderTemplate('account-list.html',[
'emails'=>$accounts,
'dateformat'=>$this->settings['DATEFORMAT']
]);
}
function deleteMail($email,$id)
{
@ -64,7 +90,7 @@ class OpenTrashmailBackend{
return '';
}
function getRawMail($email,$id)
function getRawMail($email,$id,$htmlbody=false)
{
if(!filter_var($email, FILTER_VALIDATE_EMAIL))
return $this->error('Invalid email address');
@ -73,6 +99,8 @@ class OpenTrashmailBackend{
else if(!emailIDExists($email,$id))
return $this->error('Email not found');
$emaildata = getEmail($email,$id);
if($htmlbody)
exit($emaildata['parsed']['htmlbody']);
header('Content-Type: text/plain');
echo $emaildata['raw'];
exit;

View file

@ -177,4 +177,42 @@ function generateRandomEmail()
return $adjectives[array_rand($adjectives)] . '.' . $nouns[array_rand($nouns)].'@'.$dom;
}
}
function removeScriptsFromHtml($html) {
// Remove script tags
$html = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', "", $html);
// Remove event attributes that execute scripts
$html = preg_replace('/\bon\w+="[^"]*"/i', "", $html);
// Remove href attributes that execute scripts
$html = preg_replace('/\bhref="javascript[^"]*"/i', "", $html);
// Remove any other attributes that execute scripts
$html = preg_replace('/\b\w+="[^"]*\bon\w+="[^"]*"[^>]*>/i', "", $html);
return $html;
}
function countEmailsOfAddress($email)
{
$count = 0;
if ($handle = opendir(getDirForEmail($email))) {
while (false !== ($entry = readdir($handle)))
if (endsWith($entry,'.json'))
$count++;
}
closedir($handle);
return $count;
}
function delTree($dir) {
$files = array_diff(scandir($dir), array('.','..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}

View file

@ -14,7 +14,8 @@ if($_SERVER['HTTP_HX_REQUEST']!='true')
if(count($url)==0 || !file_exists(ROOT.DS.implode('/', $url)))
if($url[0]!='api' && $url[0]!='rss')
exit($backend->renderTemplate('index.html',[
'url'=>implode('/', $url)
'url'=>implode('/', $url),
'settings'=>loadSettings(),
]));
}

View file

@ -0,0 +1,24 @@
<table>
<thead>
<tr>
<th scope="col">Email Addess</th>
<th>Emails in Inbox</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php foreach($emails as $email): ?>
<tr>
<td>
<a href="/address/<?= $email; ?>" hx-get="/api/address/<?= $email; ?>" hx-push-url="/address/<?= $email; ?>" hx-target="#main">
<?= escape($email) ?>
</a>
</td>
<td><?= countEmailsOfAddress($email); ?></td>
<td>
<input type="submit" value="Delete" hx-get="/api/deleteaccount/<?= $email ?>" hx-confirm="Are you sure to delete this account and all its emails?" hx-target="closest tr" hx-swap="outerHTML swap:1s">
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View file

@ -8,7 +8,6 @@
<article>
<header>
<p>Subject: <?= escape($emaildata['parsed']['subject']) ?></p>
<p>Received: <span id="date2-<?= $mailid ?>"><script>document.getElementById('date2-<?= $mailid ?>').innerHTML = moment.unix(parseInt(<?=$mailid?>/1000)).format('<?= $dateformat; ?>');</script></span></p>
<p>
@ -18,7 +17,14 @@
<?php endforeach; ?>
</p>
</header>
<?= nl2br(escape($emaildata['parsed']['body'])) ?>
<div id="emailbody">
<?php if($emaildata['parsed']['htmlbody']): ?>
<a href="#" hx-confirm="Warning: HTML may contain tracking functionality or scripts. Do you want to proceed?" hx-get="/api/raw-html/<?= $email ?>/<?= $mailid ?>" hx-target="#emailbody" role="button" class="secondary outline">Render email in HTML</a>
<?php endif; ?>
<hr>
<pre><?= nl2br(escape($emaildata['parsed']['body'])) ?></pre>
</div>
<footer>
Attachments
<div>

View file

@ -17,7 +17,7 @@
<li><img src="/imgs/logo_300_light.png" width="50px" /> Open Trashmail</li>
<li><input id="email" hx-post="/api/address" hx-target="#main" name="email" type="email" hx-trigger="input changed delay:500ms" placeholder="email address" aria-label="email address"></li>
<li><button hx-get="/api/random" hx-target="#main"><i class="fas fa-random"></i> Generate random</button></li>
<li><button onClick="listAddresses(event)" id="btn-list-addresses" class="btn btn-secondary my-2 my-sm-0" style="display:none;"><i class="fas fa-list"></i> List accounts</button></li>
<?php if($settings['SHOW_ACCOUNT_LIST']): ?><li><button hx-get="/api/listaccounts" hx-target="#main" hx-push-url="/listaccounts"><i class="fas fa-list"></i> List accounts</button></li><?php endif; ?>
</ul>
</nav>
</div>