created JSON API, TODO: refactor
This commit is contained in:
parent
33dedf0368
commit
75ed103d17
|
@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
- refactored code into multiple php files.
|
- refactored code into multiple php files.
|
||||||
- Requires PHP version >=7.2
|
- Requires PHP version >=7.2
|
||||||
- make all addresses lowercase #30
|
- make all addresses lowercase #30
|
||||||
|
- fixed error when downloading email
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- better horizontal spacing for header (from @Spegeli) and style
|
- better horizontal spacing for header (from @Spegeli) and style
|
||||||
|
@ -24,6 +25,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
||||||
- Blacklist some usernames, configurable #27
|
- Blacklist some usernames, configurable #27
|
||||||
- copyToClipboard button #30
|
- copyToClipboard button #30
|
||||||
- mail counter in title
|
- mail counter in title
|
||||||
|
- rest api option
|
||||||
|
|
||||||
## [0.1.4] - 2017-04-15
|
## [0.1.4] - 2017-04-15
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once './imap_client.php';
|
require_once './imap_client.php';
|
||||||
|
require_once './view.php';
|
||||||
|
|
||||||
abstract class Page {
|
|
||||||
|
abstract class Controller {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ViewHandler
|
||||||
|
*/
|
||||||
|
protected $viewHandler;
|
||||||
|
|
||||||
|
public function setViewHandler(ViewHandler $outputHandler) {
|
||||||
|
$this->viewHandler = $outputHandler;
|
||||||
|
}
|
||||||
|
|
||||||
function invoke(ImapClient $imapClient) {
|
function invoke(ImapClient $imapClient) {
|
||||||
}
|
}
|
||||||
|
@ -23,22 +34,12 @@ abstract class Page {
|
||||||
$name = $word . $nr;
|
$name = $word . $nr;
|
||||||
|
|
||||||
$domain = $domains[array_rand($domains)];
|
$domain = $domains[array_rand($domains)];
|
||||||
header("location: ?$name@$domain");
|
$this->viewHandler->newAddress("$name@$domain");
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* print error and stop program.
|
|
||||||
* @param $status integer http status
|
|
||||||
* @param $text string error text
|
|
||||||
*/
|
|
||||||
function error($status, $text) {
|
|
||||||
@http_response_code($status);
|
|
||||||
die("{\"error\": \"$text\"}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RedirectToAddressPage extends Page {
|
class RedirectToAddressController extends Controller {
|
||||||
private $username;
|
private $username;
|
||||||
private $domain;
|
private $domain;
|
||||||
private $config_blocked_usernames;
|
private $config_blocked_usernames;
|
||||||
|
@ -51,11 +52,11 @@ class RedirectToAddressPage extends Page {
|
||||||
|
|
||||||
function invoke(ImapClient $imapClient) {
|
function invoke(ImapClient $imapClient) {
|
||||||
$user = User::parseUsernameAndDomain($this->username, $this->domain, $this->config_blocked_usernames);
|
$user = User::parseUsernameAndDomain($this->username, $this->domain, $this->config_blocked_usernames);
|
||||||
header("location: ?" . $user->username . "@" . $user->domain);
|
$this->viewHandler->newAddress($user->username . "@" . $user->domain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DownloadEmailPage extends Page {
|
class DownloadEmailController extends Controller {
|
||||||
|
|
||||||
private $email_id;
|
private $email_id;
|
||||||
private $address;
|
private $address;
|
||||||
|
@ -75,21 +76,18 @@ class DownloadEmailPage extends Page {
|
||||||
$this->if_invalid_redirect_to_random($user, $this->config_domains);
|
$this->if_invalid_redirect_to_random($user, $this->config_domains);
|
||||||
|
|
||||||
$download_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
$download_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||||
if ($imapClient->load_one_email($download_email_id, $user) !== null) {
|
$full_email = $imapClient->load_one_email_fully($download_email_id, $user);
|
||||||
header("Content-Type: message/rfc822; charset=utf-8");
|
if ($full_email !== null) {
|
||||||
header("Content-Disposition: attachment; filename=\"" . $user->address . "-" . $download_email_id . ".eml\"");
|
$filename = $user->address . "-" . $download_email_id . ".eml";
|
||||||
|
$this->viewHandler->downloadEmailAsRfc822($full_email, $filename);
|
||||||
$headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
|
||||||
$body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
|
||||||
print $headers . "\n" . $body;
|
|
||||||
} else {
|
} else {
|
||||||
$this->error(404, 'download error: invalid username/mailid combination');
|
$this->viewHandler->error(404, 'download error: invalid username/mailid combination');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class DeleteEmailPage extends Page {
|
class DeleteEmailController extends Controller {
|
||||||
private $email_id;
|
private $email_id;
|
||||||
private $address;
|
private $address;
|
||||||
private $config_domains;
|
private $config_domains;
|
||||||
|
@ -108,14 +106,14 @@ class DeleteEmailPage extends Page {
|
||||||
|
|
||||||
$delete_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
$delete_email_id = filter_var($this->email_id, FILTER_SANITIZE_NUMBER_INT);
|
||||||
if ($imapClient->delete_email($delete_email_id, $user)) {
|
if ($imapClient->delete_email($delete_email_id, $user)) {
|
||||||
header("location: ?" . $user->address);
|
$this->viewHandler->done($this->address);
|
||||||
} else {
|
} else {
|
||||||
$this->error(404, 'delete error: invalid username/mailid combination');
|
$this->viewHandler->error(404, 'delete error: invalid username/mailid combination');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RedirectToRandomAddressPage extends Page {
|
class RedirectToRandomAddressController extends Controller {
|
||||||
private $config_domains;
|
private $config_domains;
|
||||||
|
|
||||||
public function __construct($config_domains) {
|
public function __construct($config_domains) {
|
||||||
|
@ -128,7 +126,7 @@ class RedirectToRandomAddressPage extends Page {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DisplayEmailsPage extends Page {
|
class DisplayEmailsController extends Controller {
|
||||||
private $address;
|
private $address;
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
@ -142,16 +140,14 @@ class DisplayEmailsPage extends Page {
|
||||||
// print emails with html template
|
// print emails with html template
|
||||||
$user = User::parseDomain($this->address, $this->config['blocked_usernames']);
|
$user = User::parseDomain($this->address, $this->config['blocked_usernames']);
|
||||||
$this->if_invalid_redirect_to_random($user, $this->config['domains']);
|
$this->if_invalid_redirect_to_random($user, $this->config['domains']);
|
||||||
|
|
||||||
// Set variables for frontend template:
|
|
||||||
$emails = $imapClient->get_emails($user);
|
$emails = $imapClient->get_emails($user);
|
||||||
$config = $this->config;
|
|
||||||
require "frontend.template.php";
|
$this->viewHandler->displayEmails($emails, $this->config, $user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class InvalidRequestPage extends Page {
|
class InvalidRequestController extends Controller {
|
||||||
function invoke(ImapClient $imapClient) {
|
function invoke(ImapClient $imapClient) {
|
||||||
$this->error(400, "Bad Request");
|
$this->viewHandler->error(400, "Bad Request");
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -184,7 +184,7 @@ $purifier = new HTMLPurifier($purifier_config);
|
||||||
|
|
||||||
<a class="btn btn-sm btn-outline-danger"
|
<a class="btn btn-sm btn-outline-danger"
|
||||||
role="button"
|
role="button"
|
||||||
href="?action=delete_email&delete_email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
href="?action=delete_email&email_id=<?php echo $safe_email_id; ?>&address=<?php echo $user->address ?>">Delete
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -54,13 +54,25 @@ class ImapClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function load_one_email_fully($download_email_id, $user) {
|
||||||
|
if ($this->load_one_email($download_email_id, $user) !== null) {
|
||||||
|
$headers = imap_fetchheader($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||||
|
$body = imap_body($this->mailbox->getImapStream(), $download_email_id, FT_UID);
|
||||||
|
return $headers . "\n" . $body;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load emails using the $mail_ids, the mails have to match the $address in TO or CC.
|
* 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 $mail_ids array of integer ids
|
||||||
* @param $user User
|
* @param $user User
|
||||||
* @return array of emails
|
* @return array of emails
|
||||||
*/
|
*/
|
||||||
private function _load_emails(array $mail_ids, User $user) {
|
private
|
||||||
|
function _load_emails(array $mail_ids, User $user) {
|
||||||
$emails = array();
|
$emails = array();
|
||||||
foreach ($mail_ids as $id) {
|
foreach ($mail_ids as $id) {
|
||||||
$mail = $this->mailbox->getMail($id);
|
$mail = $this->mailbox->getMail($id);
|
||||||
|
@ -75,7 +87,8 @@ class ImapClient {
|
||||||
/**
|
/**
|
||||||
* deletes messages older than X days.
|
* deletes messages older than X days.
|
||||||
*/
|
*/
|
||||||
public function delete_old_messages(string $delete_messages_older_than) {
|
public
|
||||||
|
function delete_old_messages(string $delete_messages_older_than) {
|
||||||
$ids = $this->mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($delete_messages_older_than)));
|
$ids = $this->mailbox->searchMailbox('BEFORE ' . date('d-M-Y', strtotime($delete_messages_older_than)));
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$this->mailbox->deleteMail($id);
|
$this->mailbox->deleteMail($id);
|
||||||
|
|
|
@ -7,13 +7,14 @@ require_once './backend-libs/autoload.php';
|
||||||
|
|
||||||
require_once './user.php';
|
require_once './user.php';
|
||||||
require_once './imap_client.php';
|
require_once './imap_client.php';
|
||||||
require_once './pages.php';
|
require_once './controller.php';
|
||||||
require_once './router.php';
|
require_once './router.php';
|
||||||
|
|
||||||
$imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']);
|
$imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']);
|
||||||
|
|
||||||
$router = new Router($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
$router = new Router($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
||||||
$page = $router->route();
|
$page = $router->route();
|
||||||
|
$page->setViewHandler(new ServerRenderViewHandler());
|
||||||
$page->invoke($imapClient);
|
$page->invoke($imapClient);
|
||||||
|
|
||||||
// delete after each request
|
// delete after each request
|
||||||
|
|
23
src/rest.php
Normal file
23
src/rest.php
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<?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';
|
||||||
|
|
||||||
|
require_once './user.php';
|
||||||
|
require_once './imap_client.php';
|
||||||
|
require_once './controller.php';
|
||||||
|
require_once './router.rest.php';
|
||||||
|
|
||||||
|
$imapClient = new ImapClient($config['imap']['url'], $config['imap']['username'], $config['imap']['password']);
|
||||||
|
|
||||||
|
$router = new RestRouter($_SERVER['REQUEST_METHOD'], $_GET['action'] ?? NULL, $_GET, $_POST, $_SERVER['QUERY_STRING'], $config);
|
||||||
|
$page = $router->route();
|
||||||
|
$page->setViewHandler(new JsonViewHandler());
|
||||||
|
$page->invoke($imapClient);
|
||||||
|
|
||||||
|
// delete after each request
|
||||||
|
$imapClient->delete_old_messages($config['delete_messages_older_than']);
|
||||||
|
|
||||||
|
?>
|
|
@ -1,15 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
require_once './pages.php';
|
require_once './controller.php';
|
||||||
|
|
||||||
class Router {
|
class Router {
|
||||||
|
|
||||||
private $method;
|
protected $method;
|
||||||
private $action;
|
protected $action;
|
||||||
private $get_vars;
|
protected $get_vars;
|
||||||
private $post_vars;
|
protected $post_vars;
|
||||||
private $query_string;
|
protected $query_string;
|
||||||
private $config;
|
protected $config;
|
||||||
|
|
||||||
public function __construct(string $method, string $action = NULL, array $get_vars, array $post_vars, string $query_string, array $config) {
|
public function __construct(string $method, string $action = NULL, array $get_vars, array $post_vars, string $query_string, array $config) {
|
||||||
$this->method = $method;
|
$this->method = $method;
|
||||||
|
@ -21,30 +21,30 @@ class Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function route(): Page {
|
function route(): Controller {
|
||||||
if ($this->action === "redirect"
|
if ($this->action === "redirect"
|
||||||
&& isset($this->post_vars['username'])
|
&& isset($this->post_vars['username'])
|
||||||
&& isset($this->post_vars['domain'])) {
|
&& isset($this->post_vars['domain'])) {
|
||||||
return new RedirectToAddressPage($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']);
|
return new RedirectToAddressController($this->post_vars['username'], $this->post_vars['domain'], $this->config['blocked_usernames']);
|
||||||
|
|
||||||
} elseif ($this->action === "download_email"
|
} elseif ($this->action === "download_email"
|
||||||
&& isset($this->get_vars['download_email_id'])
|
&& isset($this->get_vars['email_id'])
|
||||||
&& isset($this->get_vars['address'])) {
|
&& isset($this->get_vars['address'])) {
|
||||||
return new DownloadEmailPage($this->get_vars['download_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||||
|
|
||||||
} elseif ($this->action === "delete_email"
|
} elseif ($this->action === "delete_email"
|
||||||
&& isset($this->get_vars['delete_email_id'])
|
&& isset($this->get_vars['email_id'])
|
||||||
&& isset($this->get_vars['address'])) {
|
&& isset($this->get_vars['address'])) {
|
||||||
return new DeleteEmailPage($this->get_vars['delete_email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||||
|
|
||||||
} elseif ($this->action === 'random') {
|
} elseif ($this->action === 'random') {
|
||||||
return new RedirectToRandomAddressPage($this->config['domains']);
|
return new RedirectToRandomAddressController($this->config['domains']);
|
||||||
|
|
||||||
} elseif (!empty($this->query_string)) {
|
} elseif (!empty($this->query_string)) {
|
||||||
return new DisplayEmailsPage($this->query_string, $this->config);
|
return new DisplayEmailsController($this->query_string, $this->config);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return new RedirectToRandomAddressPage($this->config['domains']);
|
return new RedirectToRandomAddressController($this->config['domains']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
30
src/router.rest.php
Normal file
30
src/router.rest.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once './controller.php';
|
||||||
|
require_once './router.php';
|
||||||
|
|
||||||
|
|
||||||
|
class RestRouter extends Router {
|
||||||
|
|
||||||
|
function route(): Controller {
|
||||||
|
if ($this->action === "download_email"
|
||||||
|
&& isset($this->get_vars['email_id'])
|
||||||
|
&& isset($this->get_vars['address'])) {
|
||||||
|
return new DownloadEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||||
|
|
||||||
|
} elseif ($this->action === "delete_email"
|
||||||
|
&& isset($this->get_vars['email_id'])
|
||||||
|
&& isset($this->get_vars['address'])) {
|
||||||
|
return new DeleteEmailController($this->get_vars['email_id'], $this->get_vars['address'], $this->config['domains'], $this->config['blocked_usernames']);
|
||||||
|
|
||||||
|
} elseif ($this->action === 'get_random_username') {
|
||||||
|
return new RedirectToRandomAddressController($this->config['domains']);
|
||||||
|
|
||||||
|
} elseif ($this->action === 'get_emails' && isset($this->get_vars['address'])) {
|
||||||
|
return new DisplayEmailsController($this->get_vars['address'], $this->config);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new InvalidRequestController();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
src/view.php
Normal file
79
src/view.php
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface ViewHandler {
|
||||||
|
function done($address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* print error and stop program.
|
||||||
|
* @param $status integer http status
|
||||||
|
* @param $text string error text
|
||||||
|
*/
|
||||||
|
function error($status, $text);
|
||||||
|
|
||||||
|
function displayEmails($emails, $config, $user);
|
||||||
|
|
||||||
|
function newAddress($string);
|
||||||
|
|
||||||
|
function downloadEmailAsRfc822($full_email, $filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
class JsonViewHandler implements ViewHandler {
|
||||||
|
|
||||||
|
private function json($obj) {
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
// Never cache requests:
|
||||||
|
header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
|
||||||
|
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||||
|
header("Pragma: no-cache");
|
||||||
|
print json_encode($obj);
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
|
||||||
|
function done($address) {
|
||||||
|
$this->json(array('status' => "success"));
|
||||||
|
}
|
||||||
|
|
||||||
|
function error($status, $msg) {
|
||||||
|
@http_response_code($status);
|
||||||
|
$this->json(array('status' => "failure", 'error' => $msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayEmails($emails, $config, $user) {
|
||||||
|
$this->json(array('status' => "success", 'emails' => $emails));
|
||||||
|
}
|
||||||
|
|
||||||
|
function newAddress($address) {
|
||||||
|
$this->json(array('status' => "failure", 'address' => $address));
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadEmailAsRfc822($full_email, $filename) {
|
||||||
|
$this->json(array('status' => "success", 'body' => $full_email));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerRenderViewHandler implements ViewHandler {
|
||||||
|
function done($address) {
|
||||||
|
header("location: ?" . $address);
|
||||||
|
}
|
||||||
|
|
||||||
|
function error($status, $msg) {
|
||||||
|
@http_response_code($status);
|
||||||
|
die("{'result': 'error', 'error': '$msg'}");
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayEmails($emails, $config, $user) {
|
||||||
|
// Set variables for frontend template: $emails, $config
|
||||||
|
require "frontend.template.php";
|
||||||
|
}
|
||||||
|
|
||||||
|
function newAddress($address) {
|
||||||
|
header("location: ?$address");
|
||||||
|
}
|
||||||
|
|
||||||
|
function downloadEmailAsRfc822($full_email, $filename) {
|
||||||
|
header("Content-Type: message/rfc822; charset=utf-8");
|
||||||
|
header("Content-Disposition: attachment; filename=\"$filename\"");
|
||||||
|
print $full_email;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user