Merge 5149869952
into 8d2f592e44
This commit is contained in:
commit
e3a76b4ff7
|
@ -14,13 +14,13 @@ A **self-hosted** disposable mailbox service (aka trash mail) :cloud: :envelop
|
||||||
* Automatic refresh. Download and delete your emails.
|
* Automatic refresh. Download and delete your emails.
|
||||||
* Display emails as text or html with sanitization filter.
|
* Display emails as text or html with sanitization filter.
|
||||||
* Display emails based on one [catch-all imap mailbox](https://www.google.ch/search?q=how+to+setup+catch-all+imap+mailbox).
|
* Display emails based on one [catch-all imap mailbox](https://www.google.ch/search?q=how+to+setup+catch-all+imap+mailbox).
|
||||||
* Only requires PHP >=5.3.0 and [imap extension](http://php.net/manual/book.imap.php)
|
* Only requires PHP >=7.2 and [imap extension](http://php.net/manual/book.imap.php)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
* webserver with php >=5.3.0
|
* webserver with php >=7.2
|
||||||
* php [imap extension](http://php.net/manual/book.imap.php)
|
* php [imap extension](http://php.net/manual/book.imap.php)
|
||||||
* IMAP account and a domain with [catch-all configuration](https://www.google.ch/search?q=how+to+setup+catch-all+imap+mailbox). (all emails go to one mailbox).
|
* IMAP account and a domain with [catch-all configuration](https://www.google.ch/search?q=how+to+setup+catch-all+imap+mailbox). (all emails go to one mailbox).
|
||||||
|
|
||||||
|
|
49
src/autolink.php
Normal file
49
src/autolink.php
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -88,7 +88,7 @@ $purifier = new HTMLPurifier($purifier_config);
|
||||||
mailbox:
|
mailbox:
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
<form id="header-form" data-turbolinks-permanent action="?" method="post">
|
<form id="header-form" data-turbolinks-permanent action="?action=redirect" method="post">
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
|
|
||||||
<div class="col-lg-5 col-md-4 col-sm-6 col-xs-12">
|
<div class="col-lg-5 col-md-4 col-sm-6 col-xs-12">
|
||||||
|
@ -117,7 +117,7 @@ $purifier = new HTMLPurifier($purifier_config);
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-3 col-md-4 col-sm-12 col-xs-12 random-column">
|
<div class="col-lg-3 col-md-4 col-sm-12 col-xs-12 random-column">
|
||||||
<a role="button" href="?random=true"
|
<a role="button" href="?action=random"
|
||||||
class="btn btn-outline-primary col-sm-12 col-xs-12 random-button">Generate
|
class="btn btn-outline-primary col-sm-12 col-xs-12 random-button">Generate
|
||||||
Random</a>
|
Random</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -177,12 +177,12 @@ $purifier = new HTMLPurifier($purifier_config);
|
||||||
<div class="col-sm-4 text-right">
|
<div class="col-sm-4 text-right">
|
||||||
<a class="btn btn-sm btn-outline-primary " download="true"
|
<a class="btn btn-sm btn-outline-primary " download="true"
|
||||||
role="button"
|
role="button"
|
||||||
href="?download_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Download
|
href="?action=download_email&download_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Download
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="btn btn-sm btn-outline-danger"
|
<a class="btn btn-sm btn-outline-danger"
|
||||||
role="button"
|
role="button"
|
||||||
href="?delete_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
href="?action=delete_email&delete_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
133
src/index.php
133
src/index.php
|
@ -9,48 +9,17 @@ $mailbox = new PhpImap\Mailbox($config['imap']['url'],
|
||||||
$config['imap']['username'],
|
$config['imap']['username'],
|
||||||
$config['imap']['password']);
|
$config['imap']['password']);
|
||||||
|
|
||||||
|
require_once './user.php';
|
||||||
|
require_once './autolink.php';
|
||||||
|
require_once './pages.php';
|
||||||
|
require_once './router.php';
|
||||||
|
|
||||||
// simple router:
|
$router = new Router($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
||||||
if (isset($_POST['username']) && isset($_POST['domain'])) {
|
$page = $router->route();
|
||||||
$user = User::parseUsernameAndDomain($_POST['username'], $_POST['domain']);
|
$page->invoke();
|
||||||
header("location: ?" . $user->username . "@" . $user->domain);
|
|
||||||
exit();
|
|
||||||
} elseif (isset($_GET['download_email_id']) && isset($_GET['address'])) {
|
|
||||||
$user = User::parseDomain($_GET['address']);
|
|
||||||
$download_email_id = filter_input(INPUT_GET, 'download_email_id', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
if ($user->isInvalid()) {
|
|
||||||
redirect_to_random($config['domains']);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
download_email($download_email_id, $user);
|
|
||||||
exit();
|
|
||||||
} elseif (isset($_GET['delete_email_id']) && isset($_GET['address'])) {
|
|
||||||
$user = User::parseDomain($_GET['address']);
|
|
||||||
$delete_email_id = filter_input(INPUT_GET, 'delete_email_id', FILTER_SANITIZE_NUMBER_INT);
|
|
||||||
if ($user->isInvalid()) {
|
|
||||||
redirect_to_random($config['domains']);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
delete_email($delete_email_id, $user);
|
|
||||||
header("location: ?" . $user->address);
|
|
||||||
exit();
|
|
||||||
} elseif (isset($_GET['random'])) {
|
|
||||||
redirect_to_random($config['domains']);
|
|
||||||
exit();
|
|
||||||
} else {
|
|
||||||
// print emails with html template
|
|
||||||
$user = User::parseDomain($_SERVER['QUERY_STRING']);
|
|
||||||
if ($user->isInvalid()) {
|
|
||||||
redirect_to_random($config['domains']);
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
$emails = get_emails($user);
|
|
||||||
require "frontend.template.php";
|
|
||||||
|
|
||||||
// delete after each request
|
|
||||||
delete_old_messages();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// delete after each request
|
||||||
|
delete_old_messages();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* print error and stop program.
|
* print error and stop program.
|
||||||
|
@ -184,40 +153,6 @@ function _clean_username($address) {
|
||||||
return $username;
|
return $username;
|
||||||
}
|
}
|
||||||
|
|
||||||
class User {
|
|
||||||
public $address;
|
|
||||||
public $username;
|
|
||||||
public $domain;
|
|
||||||
|
|
||||||
public function isInvalid() {
|
|
||||||
global $config;
|
|
||||||
if (empty($this->username) || empty($this->domain)) {
|
|
||||||
return true;
|
|
||||||
} else if (!in_array($this->domain, $config['domains'])) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function parseDomain($address) {
|
|
||||||
$clean_address = _clean_address($address);
|
|
||||||
$user = new User();
|
|
||||||
$user->username = _clean_username($clean_address);
|
|
||||||
$user->domain = _clean_domain($clean_address);
|
|
||||||
$user->address = $user->username . '@' . $user->domain;
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function parseUsernameAndDomain($username, $domain) {
|
|
||||||
$user = new User();
|
|
||||||
$user->username = _clean_username($username);
|
|
||||||
$user->domain = _clean_domain($domain);
|
|
||||||
$user->address = $user->username . '@' . $user->domain;
|
|
||||||
return $user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function _clean_domain($address) {
|
function _clean_domain($address) {
|
||||||
$username = strtolower($address);
|
$username = strtolower($address);
|
||||||
|
@ -225,7 +160,7 @@ function _clean_domain($address) {
|
||||||
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
return preg_replace('/[^A-Za-z0-9_.+-]/', "", $username); // remove special characters
|
||||||
}
|
}
|
||||||
|
|
||||||
function redirect_to_random($domains) {
|
function redirect_to_random(array $domains) {
|
||||||
$wordLength = rand(3, 8);
|
$wordLength = rand(3, 8);
|
||||||
$container = new PronounceableWord_DependencyInjectionContainer();
|
$container = new PronounceableWord_DependencyInjectionContainer();
|
||||||
$generator = $container->getGenerator();
|
$generator = $container->getGenerator();
|
||||||
|
@ -251,52 +186,4 @@ function delete_old_messages() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
?>
|
114
src/pages.php
Normal file
114
src/pages.php
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class Page {
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
}
|
||||||
|
|
||||||
|
function if_invalid_redirect_to_random(User $user, array $config_domains) {
|
||||||
|
if ($user->isInvalid()) {
|
||||||
|
redirect_to_random($config_domains);
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RedirectToAddressPage extends Page {
|
||||||
|
private $username;
|
||||||
|
private $domain;
|
||||||
|
|
||||||
|
public function __construct(string $username, string $domain) {
|
||||||
|
$this->username = $username;
|
||||||
|
$this->domain = $domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
$user = User::parseUsernameAndDomain($this->username, $this->domain);
|
||||||
|
header("location: ?" . $user->username . "@" . $user->domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DownloadEmailPage extends Page {
|
||||||
|
|
||||||
|
private $email_id;
|
||||||
|
private $address;
|
||||||
|
private $config_domains;
|
||||||
|
|
||||||
|
public function __construct(string $email_id, string $address, array $config_domains) {
|
||||||
|
$this->email_id = $email_id;
|
||||||
|
$this->address = $address;
|
||||||
|
$this->config_domains = $config_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
$user = User::parseDomain($this->address);
|
||||||
|
$this->if_invalid_redirect_to_random($user, $this->config_domains);
|
||||||
|
|
||||||
|
$download_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
download_email($download_email_id, $user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteEmailPage extends Page {
|
||||||
|
private $email_id;
|
||||||
|
private $address;
|
||||||
|
private $config_domains;
|
||||||
|
|
||||||
|
public function __construct($email_id, $address, $config_domains) {
|
||||||
|
$this->email_id = $email_id;
|
||||||
|
$this->address = $address;
|
||||||
|
$this->config_domains = $config_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
$user = User::parseDomain($this->address);
|
||||||
|
$this->if_invalid_redirect_to_random($user, $this->config_domains);
|
||||||
|
|
||||||
|
$delete_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
delete_email($delete_email_id, $user);
|
||||||
|
header("location: ?" . $user->address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RedirectToRandomAddressPage extends Page {
|
||||||
|
private $config_domains;
|
||||||
|
|
||||||
|
public function __construct($config_domains) {
|
||||||
|
$this->config_domains = $config_domains;
|
||||||
|
}
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
redirect_to_random($this->config_domains);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisplayEmailsPage extends Page {
|
||||||
|
private $address;
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
public function __construct($address, $config) {
|
||||||
|
$this->address = $address;
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function invoke() {
|
||||||
|
// print emails with html template
|
||||||
|
$user = User::parseDomain($this->address);
|
||||||
|
$this->if_invalid_redirect_to_random($user, $this->config['domains']);
|
||||||
|
|
||||||
|
global $emails;
|
||||||
|
global $config;
|
||||||
|
$emails = get_emails($user);
|
||||||
|
require "frontend.template.php";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InvalidRequestPage extends Page {
|
||||||
|
function invoke() {
|
||||||
|
error(400, "Bad Request");
|
||||||
|
}
|
||||||
|
}
|
54
src/router.php
Normal file
54
src/router.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once './pages.php';
|
||||||
|
|
||||||
|
class Router {
|
||||||
|
|
||||||
|
private $method;
|
||||||
|
private $action;
|
||||||
|
private $get_vars;
|
||||||
|
private $post_vars;
|
||||||
|
private $query_string;
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
public function __construct(string $method, string $action = NULL, array $get_vars, array $post_vars, string $query_string, array $config) {
|
||||||
|
$this->method = $method;
|
||||||
|
$this->action = $action;
|
||||||
|
$this->get_vars = $get_vars;
|
||||||
|
$this->post_vars = $post_vars;
|
||||||
|
$this->query_string = $query_string;
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function route(): Page {
|
||||||
|
if ($this->action === "redirect"
|
||||||
|
&& isset($this->post_vars['username'])
|
||||||
|
&& isset($this->post_vars['domain'])) {
|
||||||
|
return new RedirectToAddressPage($this->post_vars['username'], $this->post_vars['domain']);
|
||||||
|
|
||||||
|
} elseif ($this->action === "download_email"
|
||||||
|
&& isset($this->get_vars['download_email_id'])
|
||||||
|
&& isset($this->get_vars['address'])) {
|
||||||
|
return new DownloadEmailPage($this->get_vars['download_email_id'], $this->get_vars['address'], $this->config['domains']);
|
||||||
|
|
||||||
|
} elseif ($this->action === "delete_email"
|
||||||
|
&& isset($this->get_vars['delete_email_id'])
|
||||||
|
&& isset($this->get_vars['address'])) {
|
||||||
|
return new DeleteEmailPage($this->get_vars['delete_email_id'], $this->get_vars['address'], $this->config['domains']);
|
||||||
|
|
||||||
|
} elseif ($this->action === 'random') {
|
||||||
|
return new RedirectToRandomAddressPage($this->config['domains']);
|
||||||
|
|
||||||
|
} elseif (empty($this->query_string)) {
|
||||||
|
return new RedirectToRandomAddressPage($this->config['domains']);
|
||||||
|
|
||||||
|
} elseif (!empty($this->query_string)) {
|
||||||
|
return new DisplayEmailsPage($this->query_string, $this->config);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new InvalidRequestPage();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
src/user.php
Normal file
35
src/user.php
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class User {
|
||||||
|
public $address;
|
||||||
|
public $username;
|
||||||
|
public $domain;
|
||||||
|
|
||||||
|
public function isInvalid(): bool {
|
||||||
|
global $config;
|
||||||
|
if (empty($this->username) || empty($this->domain)) {
|
||||||
|
return true;
|
||||||
|
} else if (!in_array($this->domain, $config['domains'])) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseDomain(string $address): User {
|
||||||
|
$clean_address = _clean_address($address);
|
||||||
|
$user = new User();
|
||||||
|
$user->username = _clean_username($clean_address);
|
||||||
|
$user->domain = _clean_domain($clean_address);
|
||||||
|
$user->address = $user->username . '@' . $user->domain;
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseUsernameAndDomain(string $username, string $domain): User {
|
||||||
|
$user = new User();
|
||||||
|
$user->username = _clean_username($username);
|
||||||
|
$user->domain = _clean_domain($domain);
|
||||||
|
$user->address = $user->username . '@' . $user->domain;
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user