moved html to template file
This commit is contained in:
parent
f49c16d62e
commit
ea6b9b7039
235
src/backend.php
235
src/backend.php
|
@ -1,235 +0,0 @@
|
|||
<?php
|
||||
# set the new path of config.php (must be in a safe location outside the `public_html`)
|
||||
require_once '../../config.php';
|
||||
|
||||
# load php dependencies:
|
||||
require_once './backend-libs/autoload.php';
|
||||
|
||||
$mailbox = new PhpImap\Mailbox($config['imap']['url'],
|
||||
$config['imap']['username'],
|
||||
$config['imap']['password']);
|
||||
|
||||
/**
|
||||
* print error and stop program.
|
||||
* @param $status integer http status
|
||||
* @param $text string error text
|
||||
*/
|
||||
function error($status, $text) {
|
||||
@http_response_code($status);
|
||||
@print("{\"error\": \"$text\"}");
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* print all mails for the given $user.
|
||||
* @param $address string email address
|
||||
* @return array
|
||||
*/
|
||||
function get_emails($address) {
|
||||
global $mailbox;
|
||||
|
||||
// Search for mails with the recipient $address in TO or CC.
|
||||
$mailsIdsTo = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'TO "' . $address . '"');
|
||||
$mailsIdsCc = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'CC "' . $address . '"');
|
||||
$mail_ids = array_merge($mailsIdsTo, $mailsIdsCc);
|
||||
|
||||
$emails = _load_emails($mail_ids, $address);
|
||||
return $emails;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* deletes emails by id and username. The $address must match the recipient in the email.
|
||||
*
|
||||
* @param $mailid integer imap email id
|
||||
* @param $address string email address
|
||||
* @internal param the $username matching username
|
||||
*/
|
||||
function delete_email($mailid, $address) {
|
||||
global $mailbox;
|
||||
|
||||
if (_load_one_email($mailid, $address) !== null) {
|
||||
$mailbox->deleteMail($mailid);
|
||||
$mailbox->expungeDeletedMails();
|
||||
} else {
|
||||
error(404, 'delete error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* download email by id and username. The $address must match the recipient in the email.
|
||||
*
|
||||
* @param $mailid integer imap email id
|
||||
* @param $address string email address
|
||||
* @internal param the $username matching username
|
||||
*/
|
||||
|
||||
function download_email($mailid, $address) {
|
||||
global $mailbox;
|
||||
|
||||
if (_load_one_email($mailid, $address) !== null) {
|
||||
header("Content-Type: message/rfc822; charset=utf-8");
|
||||
header("Content-Disposition: attachment; filename=\"$address-$mailid.eml\"");
|
||||
|
||||
$headers = imap_fetchheader($mailbox->getImapStream(), $mailid, FT_UID);
|
||||
$body = imap_body($mailbox->getImapStream(), $mailid, FT_UID);
|
||||
print ($headers . "\n" . $body);
|
||||
} else {
|
||||
error(404, 'download error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load exactly one email, the $address in TO or CC has to match.
|
||||
* @param $mailid integer
|
||||
* @param $address String address
|
||||
* @return email or null
|
||||
*/
|
||||
function _load_one_email($mailid, $address) {
|
||||
// in order to avoid https://www.owasp.org/index.php/Top_10_2013-A4-Insecure_Direct_Object_References
|
||||
// the recipient in the email has to match the $address.
|
||||
$emails = _load_emails(array($mailid), $address);
|
||||
return count($emails) === 1 ? $emails[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load emails using the $mail_ids, the mails have to match the $address in TO or CC.
|
||||
* @param $mail_ids array of integer ids
|
||||
* @param $address String address
|
||||
* @return array of emails
|
||||
*/
|
||||
function _load_emails($mail_ids, $address) {
|
||||
global $mailbox;
|
||||
|
||||
$emails = array();
|
||||
foreach ($mail_ids as $id) {
|
||||
$mail = $mailbox->getMail($id);
|
||||
// imap_search also returns partials matches. The mails have to be filtered again:
|
||||
if (array_key_exists($address, $mail->to) || array_key_exists($address, $mail->cc)) {
|
||||
$emails[] = $mail;
|
||||
}
|
||||
}
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove illegal characters from username and remove everything after the @-sign. You may extend it if your server supports them.
|
||||
* @param $username
|
||||
* @return string clean username
|
||||
*/
|
||||
function _clean_username($username) {
|
||||
$username = strtolower($username);
|
||||
$username = preg_replace('/@.*$/', "", $username); // remove part after @
|
||||
$username = preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||
|
||||
if (in_array($username, array('root', 'admin', 'administrator', 'hostmaster', 'postmaster', 'webmaster'))) {
|
||||
// Forbidden name!
|
||||
return '';
|
||||
}
|
||||
|
||||
return $username;
|
||||
}
|
||||
|
||||
function _clean_domain($username) {
|
||||
$username = strtolower($username);
|
||||
$username = preg_replace('/^.*@/', "", $username); // remove part before @
|
||||
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||
}
|
||||
|
||||
function redirect_to_random($domains) {
|
||||
$wordLength = rand(3, 8);
|
||||
$container = new PronounceableWord_DependencyInjectionContainer();
|
||||
$generator = $container->getGenerator();
|
||||
$word = $generator->generateWordOfGivenLength($wordLength);
|
||||
$nr = rand(51, 91);
|
||||
$name = $word . $nr;
|
||||
|
||||
$domain = $domains[array_rand($domains)];
|
||||
header("location: ?$name@$domain");
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes messages older than X days.
|
||||
*/
|
||||
function delete_old_messages() {
|
||||
global $mailbox, $config;
|
||||
|
||||
$ids = $mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($config['delete_messages_older_than'])));
|
||||
foreach ($ids as $id) {
|
||||
$mailbox->deleteMail($id);
|
||||
}
|
||||
$mailbox->expungeDeletedMails();
|
||||
}
|
||||
|
||||
|
||||
class AutoLinkExtension {
|
||||
static public function auto_link_text($string) {
|
||||
|
||||
$string = preg_replace_callback("/
|
||||
((?<![\"']) # don't look inside quotes
|
||||
(\b
|
||||
( # protocol or www.
|
||||
[a-z]{3,}:\/\/
|
||||
|
|
||||
www\.
|
||||
)
|
||||
(?: # domain
|
||||
[a-zA-Z0-9_\-]+
|
||||
(?:\.[a-zA-Z0-9_\-]+)*
|
||||
|
|
||||
localhost
|
||||
)
|
||||
(?: # port
|
||||
\:[0-9]+
|
||||
)?
|
||||
(?: # path
|
||||
\/[a-z0-9:%_|~.-]*
|
||||
(?:\/[a-z0-9:%_|~.-]*)*
|
||||
)?
|
||||
(?: # attributes
|
||||
\?[a-z0-9:%_|~.=&#;-]*
|
||||
)?
|
||||
(?: # anchor
|
||||
\#[a-z0-9:%_|~.=&#;-]*
|
||||
)?
|
||||
)
|
||||
(?![\"']))
|
||||
/ix", function ($match) {
|
||||
$url = $match[0];
|
||||
$href = $url;
|
||||
|
||||
if (false === strpos($href, 'http')) {
|
||||
$href = 'http://' . $href;
|
||||
}
|
||||
return '<a href="' . $href . '" rel="noreferrer">' . $url . '</a>';
|
||||
}
|
||||
, $string);
|
||||
|
||||
|
||||
$string = AutoLinkExtension::unescape($string);
|
||||
|
||||
return $string;
|
||||
} # filter()
|
||||
|
||||
/**
|
||||
* unescape()
|
||||
*
|
||||
* @param string $text
|
||||
* @return string $text
|
||||
**/
|
||||
static function unescape($text) {
|
||||
global $escape_autolink_uri;
|
||||
|
||||
if (!$escape_autolink_uri)
|
||||
return $text;
|
||||
|
||||
$unescape = array_reverse($escape_autolink_uri);
|
||||
|
||||
return str_replace(array_keys($unescape), array_values($unescape), $text);
|
||||
} # unescape()
|
||||
|
||||
}
|
||||
|
||||
|
||||
// run on every request
|
||||
delete_old_messages();
|
271
src/frontend.template.php
Normal file
271
src/frontend.template.php
Normal file
|
@ -0,0 +1,271 @@
|
|||
<?php
|
||||
/*
|
||||
input:
|
||||
|
||||
$address - username and domain
|
||||
$username - username
|
||||
$userDomain - domain
|
||||
|
||||
$config - config array
|
||||
|
||||
$emails - array of emails
|
||||
|
||||
*/
|
||||
|
||||
// Load HTML Purifier
|
||||
$purifier_config = HTMLPurifier_Config::createDefault();
|
||||
$purifier_config->set('HTML.Nofollow', true);
|
||||
$purifier_config->set('HTML.ForbiddenElements', array("img"));
|
||||
$purifier = new HTMLPurifier($purifier_config);
|
||||
|
||||
?>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?php echo $address ?></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.gif">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
|
||||
integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi"
|
||||
crossorigin="anonymous">
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="spinner.css">
|
||||
<script src="turbolinks.js"></script>
|
||||
<meta name="turbolinks-cache-control" content="no-preview">
|
||||
|
||||
<script>
|
||||
// https://stackoverflow.com/a/44353026
|
||||
var reloadWithTurbolinks = (function () {
|
||||
var scrollPosition;
|
||||
|
||||
function reload() {
|
||||
Turbolinks.visit(window.location.toString(), {action: 'replace'})
|
||||
}
|
||||
|
||||
document.addEventListener('turbolinks:before-render', function () {
|
||||
scrollPosition = [window.scrollX, window.scrollY];
|
||||
});
|
||||
|
||||
document.addEventListener('turbolinks:load', function () {
|
||||
if (scrollPosition) {
|
||||
window.scrollTo.apply(window, scrollPosition);
|
||||
scrollPosition = null
|
||||
}
|
||||
});
|
||||
|
||||
return reload;
|
||||
})();
|
||||
|
||||
|
||||
setInterval(function () {
|
||||
reloadWithTurbolinks();
|
||||
}, 15000);
|
||||
|
||||
|
||||
function showHtml(id) {
|
||||
document.getElementById('email-' + id + '-html').style.display = 'block';
|
||||
document.getElementById('email-' + id + '-plain').style.display = 'none';
|
||||
document.getElementById('show-html-button-' + id).style.display = 'none';
|
||||
document.getElementById('show-plain-button-' + id).style.display = 'inline-block';
|
||||
return false;
|
||||
}
|
||||
|
||||
function showPlain(id) {
|
||||
document.getElementById('email-' + id + '-html').style.display = 'none';
|
||||
document.getElementById('email-' + id + '-plain').style.display = 'block';
|
||||
document.getElementById('show-html-button-' + id).style.display = 'inline-block';
|
||||
document.getElementById('show-plain-button-' + id).style.display = 'none';
|
||||
return false;
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
<body data-turbolinks="false">
|
||||
|
||||
<header data-turbolinks-permanent id="header">
|
||||
<div class="container">
|
||||
<small class="form-text text-muted">
|
||||
change username:
|
||||
</small>
|
||||
|
||||
<form action="?" method="get">
|
||||
<div class="form-group row">
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input id="username" class="form-control form-control-lg" name="username" title="username"
|
||||
value="<?php echo $username ?>">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<?php
|
||||
if (count($config['domains']) == 1) {
|
||||
print "<h3>@" . $config['domains'][0] . "</h3>";
|
||||
} else {
|
||||
?>
|
||||
<select id="domain" class="form-control form-control-lg" name="domain" title="domain"
|
||||
onchange="this.form.submit()">
|
||||
<?php
|
||||
foreach ($config['domains'] as $domain) {
|
||||
$selected = $domain === $userDomain ? ' selected ' : '';
|
||||
print "<option value='$domain' $selected>@$domain</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-3 random-column">
|
||||
<span>or </span>
|
||||
<a role="button" href="?random=true" class="btn btn-outline-primary">generate random
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<main>
|
||||
<div class="container min-height">
|
||||
|
||||
<?php
|
||||
if (empty($emails)) {
|
||||
?>
|
||||
<div>
|
||||
<div class="card waiting-screen">
|
||||
<div class="card-block">
|
||||
<p class="lead">Your mailbox <strong
|
||||
><?php echo $address ?></strong> is ready. </p>
|
||||
<p>Emails will appear here automatically. They will be deleted after 30 days.</p>
|
||||
<div class="spinner">
|
||||
<div class="rect1"></div>
|
||||
<div class="rect2"></div>
|
||||
<div class="rect3"></div>
|
||||
<div class="rect4"></div>
|
||||
<div class="rect5"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
|
||||
foreach ($emails as $email) {
|
||||
|
||||
?>
|
||||
|
||||
<div class="email-table">
|
||||
|
||||
<div class="card email">
|
||||
<div class="card-block header-shadow sticky-header">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h3 class="card-title">
|
||||
<?php echo filter_var($email->subject, FILTER_SANITIZE_SPECIAL_CHARS); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-sm-4 text-right">
|
||||
<form class="form-inline float-xs-right">
|
||||
|
||||
<button type="button" class="btn btn-outline-info btn-sm"
|
||||
style="display: inline-block"
|
||||
id="show-html-button-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>"
|
||||
onclick="showHtml(<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>)">
|
||||
show html
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-info btn-sm"
|
||||
style="display: none"
|
||||
id="show-plain-button-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>"
|
||||
onclick="showPlain(<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>)">
|
||||
show text
|
||||
</button>
|
||||
|
||||
<a class="btn btn-sm btn-outline-primary " download="true"
|
||||
role="button"
|
||||
href="?download_email_id=<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>&address=<?php echo $address ?>">Download
|
||||
</a>
|
||||
|
||||
<a class="btn btn-sm btn-outline-danger"
|
||||
role="button"
|
||||
href="?delete_email_id=<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>&address=<?php echo $address ?>">Delete
|
||||
</a>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h6 class="card-subtitle mt-1 text-muted">
|
||||
<?php
|
||||
echo filter_var($email->fromName, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
echo ' <';
|
||||
echo filter_var($email->fromAddress, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
echo '>';
|
||||
?>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<h6 class="card-subtitle mt-1 text-muted"
|
||||
style="text-align: right">
|
||||
<?php echo filter_var($email->date, FILTER_SANITIZE_SPECIAL_CHARS); ?>
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-block">
|
||||
<h6 class="card-subtitle text-muted">
|
||||
To: <?php echo filter_var($email->toString, FILTER_SANITIZE_SPECIAL_CHARS); ?></h6>
|
||||
|
||||
<?php
|
||||
foreach ($email->cc as $cc) {
|
||||
print "<h6 class='card-subtitle text-muted'>CC: " . filter_var($cc, FILTER_SANITIZE_SPECIAL_CHARS) . "</h6>";
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<div class="mt-2 card-text">
|
||||
<!-- show plaintext or html -->
|
||||
<div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-plain"
|
||||
style="display: block;">
|
||||
<?php $text = filter_var($email->textPlain, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
// Keep newlines
|
||||
$text = str_replace(' ', '<br />', $text);
|
||||
echo \AutoLinkExtension::auto_link_text($text)
|
||||
?>
|
||||
</div>
|
||||
<div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-html"
|
||||
style="display: none;">
|
||||
<?php
|
||||
$clean_html = $purifier->purify($email->textHtml);
|
||||
echo $clean_html;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
<p>Powered by <a
|
||||
href="https://github.com/synox/disposable-mailbox"><strong>synox/disposable-mailbox</strong></a>
|
||||
| <a href="https://github.com/synox/disposable-mailbox"><span class="octicon octicon-mark-github"></span>
|
||||
Fork
|
||||
me on github</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
491
src/index.php
491
src/index.php
|
@ -1,10 +1,14 @@
|
|||
<?php
|
||||
require_once('backend.php');
|
||||
# set the new path of config.php (must be in a safe location outside the `public_html`)
|
||||
require_once '../../config.php';
|
||||
|
||||
# load php dependencies:
|
||||
require_once './backend-libs/autoload.php';
|
||||
|
||||
$mailbox = new PhpImap\Mailbox($config['imap']['url'],
|
||||
$config['imap']['username'],
|
||||
$config['imap']['password']);
|
||||
|
||||
$purifier_config = HTMLPurifier_Config::createDefault();
|
||||
$purifier_config->set('HTML.Nofollow', true);
|
||||
$purifier_config->set('HTML.ForbiddenElements', array("img"));
|
||||
$purifier = new HTMLPurifier($purifier_config);
|
||||
|
||||
// simple router:
|
||||
if (isset($_GET['username']) && isset($_GET['domain'])) {
|
||||
|
@ -35,257 +39,232 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
|
|||
exit();
|
||||
}
|
||||
$emails = get_emails($address);
|
||||
?>
|
||||
require "frontend.template.php";
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?php echo $address ?></title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.gif">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/css/bootstrap.min.css"
|
||||
integrity="sha384-AysaV+vQoT3kOAXZkl02PThvDr8HYKPZhNT5h/CXfBThSRXQ6jW5DO2ekP5ViFdi"
|
||||
crossorigin="anonymous">
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="spinner.css">
|
||||
<script src="turbolinks.js"></script>
|
||||
<meta name="turbolinks-cache-control" content="no-preview">
|
||||
|
||||
<script>
|
||||
// https://stackoverflow.com/a/44353026
|
||||
var reloadWithTurbolinks = (function () {
|
||||
var scrollPosition;
|
||||
|
||||
function reload() {
|
||||
Turbolinks.visit(window.location.toString(), {action: 'replace'})
|
||||
}
|
||||
|
||||
document.addEventListener('turbolinks:before-render', function () {
|
||||
scrollPosition = [window.scrollX, window.scrollY];
|
||||
});
|
||||
|
||||
document.addEventListener('turbolinks:load', function () {
|
||||
if (scrollPosition) {
|
||||
window.scrollTo.apply(window, scrollPosition);
|
||||
scrollPosition = null
|
||||
}
|
||||
});
|
||||
|
||||
return reload
|
||||
})();
|
||||
|
||||
|
||||
setInterval(function () {
|
||||
reloadWithTurbolinks();
|
||||
}, 15000);
|
||||
|
||||
|
||||
function showHtml(id) {
|
||||
document.getElementById('email-' + id + '-html').style.display = 'block';
|
||||
document.getElementById('email-' + id + '-plain').style.display = 'none';
|
||||
document.getElementById('show-html-button-' + id).style.display = 'none';
|
||||
document.getElementById('show-plain-button-' + id).style.display = 'inline-block';
|
||||
return false;
|
||||
}
|
||||
|
||||
function showPlain(id) {
|
||||
document.getElementById('email-' + id + '-html').style.display = 'none';
|
||||
document.getElementById('email-' + id + '-plain').style.display = 'block';
|
||||
document.getElementById('show-html-button-' + id).style.display = 'inline-block';
|
||||
document.getElementById('show-plain-button-' + id).style.display = 'none';
|
||||
return false;
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
<body data-turbolinks="false">
|
||||
|
||||
<header data-turbolinks-permanent id="header">
|
||||
<div class="container">
|
||||
<small class="form-text text-muted">
|
||||
change username:
|
||||
</small>
|
||||
|
||||
<form action="?" method="get">
|
||||
<div class="form-group row">
|
||||
|
||||
<div class="col-sm-4">
|
||||
<input id="username" class="form-control form-control-lg" name="username" title="username"
|
||||
value="<?php echo $username ?>">
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<?php
|
||||
if (count($config['domains']) == 1) {
|
||||
print "<h3>@" . $config['domains'][0] . "</h3>";
|
||||
} else {
|
||||
?>
|
||||
<select id="domain" class="form-control form-control-lg" name="domain" title="domain">
|
||||
<?php
|
||||
foreach ($config['domains'] as $domain) {
|
||||
$selected = $domain === $userDomain ? ' selected ' : '';
|
||||
print "<option value='$domain' $selected>@$domain</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div class="col-sm-3 random-column">
|
||||
<span>or </span>
|
||||
<a role="button" href="?random=true" class="btn btn-outline-primary">generate random
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<main>
|
||||
<div class="container min-height">
|
||||
|
||||
<?php
|
||||
if (empty($emails)) {
|
||||
?>
|
||||
<div>
|
||||
<div class="card waiting-screen">
|
||||
<div class="card-block">
|
||||
<p class="lead">Your mailbox <strong
|
||||
><?php echo $address ?></strong> is ready. </p>
|
||||
<p>Emails will appear here automatically. They will be deleted after 30 days.</p>
|
||||
<div class="spinner">
|
||||
<div class="rect1"></div>
|
||||
<div class="rect2"></div>
|
||||
<div class="rect3"></div>
|
||||
<div class="rect4"></div>
|
||||
<div class="rect5"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
|
||||
foreach ($emails as $email) {
|
||||
|
||||
?>
|
||||
|
||||
<div class="email-table">
|
||||
|
||||
<div class="card email">
|
||||
<div class="card-block header-shadow sticky-header">
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h3 class="card-title">
|
||||
<?php echo filter_var($email->subject, FILTER_SANITIZE_SPECIAL_CHARS); ?>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="col-sm-4 text-right">
|
||||
<form class="form-inline float-xs-right">
|
||||
|
||||
<button type="button" class="btn btn-outline-info btn-sm"
|
||||
style="display: inline-block"
|
||||
id="show-html-button-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>"
|
||||
onclick="showHtml(<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>)">
|
||||
show html
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-info btn-sm"
|
||||
style="display: none"
|
||||
id="show-plain-button-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>"
|
||||
onclick="showPlain(<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>)">
|
||||
show text
|
||||
</button>
|
||||
|
||||
<a class="btn btn-sm btn-outline-primary " download="true"
|
||||
role="button"
|
||||
href="?download_email_id=<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>&address=<?php echo $address ?>">Download
|
||||
</a>
|
||||
|
||||
<a class="btn btn-sm btn-outline-danger"
|
||||
role="button"
|
||||
href="?delete_email_id=<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>&address=<?php echo $address ?>">Delete
|
||||
</a>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-8">
|
||||
<h6 class="card-subtitle mt-1 text-muted">
|
||||
<?php
|
||||
echo filter_var($email->fromName, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
echo ' <';
|
||||
echo filter_var($email->fromAddress, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
echo '>';
|
||||
?>
|
||||
</h6>
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<h6 class="card-subtitle mt-1 text-muted"
|
||||
style="text-align: right">
|
||||
<?php echo filter_var($email->date, FILTER_SANITIZE_SPECIAL_CHARS); ?>
|
||||
</h6>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-block">
|
||||
<h6 class="card-subtitle text-muted">
|
||||
To: <?php echo filter_var($email->toString, FILTER_SANITIZE_SPECIAL_CHARS); ?></h6>
|
||||
|
||||
<?php
|
||||
foreach ($email->cc as $cc) {
|
||||
print "<h6 class='card-subtitle text-muted'>CC: " . filter_var($cc, FILTER_SANITIZE_SPECIAL_CHARS) . "</h6>";
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
<div class="mt-2 card-text">
|
||||
<!-- show plaintext or html -->
|
||||
<div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-plain"
|
||||
style="display: block;">
|
||||
<?php $text = filter_var($email->textPlain, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
// Keep newlines
|
||||
$text = str_replace(' ', '<br />', $text);
|
||||
echo \AutoLinkExtension::auto_link_text($text)
|
||||
?>
|
||||
</div>
|
||||
<div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-html"
|
||||
style="display: none;">
|
||||
<?php
|
||||
$clean_html = $purifier->purify($email->textHtml);
|
||||
echo $clean_html;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
<p>Powered by <a
|
||||
href="https://github.com/synox/disposable-mailbox"><strong>synox/disposable-mailbox</strong></a>
|
||||
| <a href="https://github.com/synox/disposable-mailbox"><span class="octicon octicon-mark-github"></span>
|
||||
Fork
|
||||
me on github</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
// run on every request
|
||||
delete_old_messages();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* print error and stop program.
|
||||
* @param $status integer http status
|
||||
* @param $text string error text
|
||||
*/
|
||||
function error($status, $text) {
|
||||
@http_response_code($status);
|
||||
@print("{\"error\": \"$text\"}");
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* print all mails for the given $user.
|
||||
* @param $address string email address
|
||||
* @return array
|
||||
*/
|
||||
function get_emails($address) {
|
||||
global $mailbox;
|
||||
|
||||
// Search for mails with the recipient $address in TO or CC.
|
||||
$mailsIdsTo = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'TO "' . $address . '"');
|
||||
$mailsIdsCc = imap_sort($mailbox->getImapStream(), SORTARRIVAL, true, SE_UID, 'CC "' . $address . '"');
|
||||
$mail_ids = array_merge($mailsIdsTo, $mailsIdsCc);
|
||||
|
||||
$emails = _load_emails($mail_ids, $address);
|
||||
return $emails;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* deletes emails by id and username. The $address must match the recipient in the email.
|
||||
*
|
||||
* @param $mailid integer imap email id
|
||||
* @param $address string email address
|
||||
* @internal param the $username matching username
|
||||
*/
|
||||
function delete_email($mailid, $address) {
|
||||
global $mailbox;
|
||||
|
||||
if (_load_one_email($mailid, $address) !== null) {
|
||||
$mailbox->deleteMail($mailid);
|
||||
$mailbox->expungeDeletedMails();
|
||||
} else {
|
||||
error(404, 'delete error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* download email by id and username. The $address must match the recipient in the email.
|
||||
*
|
||||
* @param $mailid integer imap email id
|
||||
* @param $address string email address
|
||||
* @internal param the $username matching username
|
||||
*/
|
||||
|
||||
function download_email($mailid, $address) {
|
||||
global $mailbox;
|
||||
|
||||
if (_load_one_email($mailid, $address) !== null) {
|
||||
header("Content-Type: message/rfc822; charset=utf-8");
|
||||
header("Content-Disposition: attachment; filename=\"$address-$mailid.eml\"");
|
||||
|
||||
$headers = imap_fetchheader($mailbox->getImapStream(), $mailid, FT_UID);
|
||||
$body = imap_body($mailbox->getImapStream(), $mailid, FT_UID);
|
||||
print ($headers . "\n" . $body);
|
||||
} else {
|
||||
error(404, 'download error: invalid username/mailid combination');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load exactly one email, the $address in TO or CC has to match.
|
||||
* @param $mailid integer
|
||||
* @param $address String address
|
||||
* @return email or null
|
||||
*/
|
||||
function _load_one_email($mailid, $address) {
|
||||
// in order to avoid https://www.owasp.org/index.php/Top_10_2013-A4-Insecure_Direct_Object_References
|
||||
// the recipient in the email has to match the $address.
|
||||
$emails = _load_emails(array($mailid), $address);
|
||||
return count($emails) === 1 ? $emails[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load emails using the $mail_ids, the mails have to match the $address in TO or CC.
|
||||
* @param $mail_ids array of integer ids
|
||||
* @param $address String address
|
||||
* @return array of emails
|
||||
*/
|
||||
function _load_emails($mail_ids, $address) {
|
||||
global $mailbox;
|
||||
|
||||
$emails = array();
|
||||
foreach ($mail_ids as $id) {
|
||||
$mail = $mailbox->getMail($id);
|
||||
// imap_search also returns partials matches. The mails have to be filtered again:
|
||||
if (array_key_exists($address, $mail->to) || array_key_exists($address, $mail->cc)) {
|
||||
$emails[] = $mail;
|
||||
}
|
||||
}
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove illegal characters from username and remove everything after the @-sign. You may extend it if your server supports them.
|
||||
* @param $username
|
||||
* @return string clean username
|
||||
*/
|
||||
function _clean_username($username) {
|
||||
$username = strtolower($username);
|
||||
$username = preg_replace('/@.*$/', "", $username); // remove part after @
|
||||
$username = preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||
|
||||
if (in_array($username, array('root', 'admin', 'administrator', 'hostmaster', 'postmaster', 'webmaster'))) {
|
||||
// Forbidden name!
|
||||
return '';
|
||||
}
|
||||
|
||||
return $username;
|
||||
}
|
||||
|
||||
function _clean_domain($username) {
|
||||
$username = strtolower($username);
|
||||
$username = preg_replace('/^.*@/', "", $username); // remove part before @
|
||||
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||
}
|
||||
|
||||
function redirect_to_random($domains) {
|
||||
$wordLength = rand(3, 8);
|
||||
$container = new PronounceableWord_DependencyInjectionContainer();
|
||||
$generator = $container->getGenerator();
|
||||
$word = $generator->generateWordOfGivenLength($wordLength);
|
||||
$nr = rand(51, 91);
|
||||
$name = $word . $nr;
|
||||
|
||||
$domain = $domains[array_rand($domains)];
|
||||
header("location: ?$name@$domain");
|
||||
}
|
||||
|
||||
/**
|
||||
* deletes messages older than X days.
|
||||
*/
|
||||
function delete_old_messages() {
|
||||
global $mailbox, $config;
|
||||
|
||||
$ids = $mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($config['delete_messages_older_than'])));
|
||||
foreach ($ids as $id) {
|
||||
$mailbox->deleteMail($id);
|
||||
}
|
||||
$mailbox->expungeDeletedMails();
|
||||
}
|
||||
|
||||
|
||||
class AutoLinkExtension {
|
||||
static public function auto_link_text($string) {
|
||||
|
||||
$string = preg_replace_callback("/
|
||||
((?<![\"']) # don't look inside quotes
|
||||
(\b
|
||||
( # protocol or www.
|
||||
[a-z]{3,}:\/\/
|
||||
|
|
||||
www\.
|
||||
)
|
||||
(?: # domain
|
||||
[a-zA-Z0-9_\-]+
|
||||
(?:\.[a-zA-Z0-9_\-]+)*
|
||||
|
|
||||
localhost
|
||||
)
|
||||
(?: # port
|
||||
\:[0-9]+
|
||||
)?
|
||||
(?: # path
|
||||
\/[a-z0-9:%_|~.-]*
|
||||
(?:\/[a-z0-9:%_|~.-]*)*
|
||||
)?
|
||||
(?: # attributes
|
||||
\?[a-z0-9:%_|~.=&#;-]*
|
||||
)?
|
||||
(?: # anchor
|
||||
\#[a-z0-9:%_|~.=&#;-]*
|
||||
)?
|
||||
)
|
||||
(?![\"']))
|
||||
/ix", function ($match) {
|
||||
$url = $match[0];
|
||||
$href = $url;
|
||||
|
||||
if (false === strpos($href, 'http')) {
|
||||
$href = 'http://' . $href;
|
||||
}
|
||||
return '<a href="' . $href . '" rel="noreferrer">' . $url . '</a>';
|
||||
}
|
||||
, $string);
|
||||
|
||||
|
||||
$string = AutoLinkExtension::unescape($string);
|
||||
|
||||
return $string;
|
||||
} # filter()
|
||||
|
||||
/**
|
||||
* unescape()
|
||||
*
|
||||
* @param string $text
|
||||
* @return string $text
|
||||
**/
|
||||
static function unescape($text) {
|
||||
global $escape_autolink_uri;
|
||||
|
||||
if (!$escape_autolink_uri)
|
||||
return $text;
|
||||
|
||||
$unescape = array_reverse($escape_autolink_uri);
|
||||
|
||||
return str_replace(array_keys($unescape), array_values($unescape), $text);
|
||||
} # unescape()
|
||||
|
||||
}
|
||||
|
||||
?>
|
Loading…
Reference in New Issue
Block a user