autolink and html support

This commit is contained in:
Synox 2018-01-09 20:33:09 +01:00
parent 9e36b93ec6
commit 015b424f0d
8 changed files with 249 additions and 19 deletions

View file

@ -1,7 +1,8 @@
{ {
"require": { "require": {
"php-imap/php-imap": "~2.0", "php-imap/php-imap": "~2.0",
"gnugat/PronounceableWord": "*" "gnugat/PronounceableWord": "*",
"ezyang/htmlpurifier": "^4.9"
}, },
"config": { "config": {
"vendor-dir": "src/backend-libs" "vendor-dir": "src/backend-libs"

51
composer.lock generated
View file

@ -4,9 +4,56 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "781cc38d2f745ec4bfba29e440111b80", "hash": "c071b40be7f9bdf56a06a9e52d220684",
"content-hash": "70878ea12bce14861844baa8032688de", "content-hash": "31df20b392f8545dda12635a78572bf7",
"packages": [ "packages": [
{
"name": "ezyang/htmlpurifier",
"version": "v4.9.3",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "95e1bae3182efc0f3422896a3236e991049dac69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/95e1bae3182efc0f3422896a3236e991049dac69",
"reference": "95e1bae3182efc0f3422896a3236e991049dac69",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "^1.1"
},
"type": "library",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
],
"time": "2017-06-03 02:28:16"
},
{ {
"name": "gnugat/PronounceableWord", "name": "gnugat/PronounceableWord",
"version": "2.0.0", "version": "2.0.0",

View file

@ -8,4 +8,5 @@ $baseDir = dirname(dirname($vendorDir));
return array( return array(
'PronounceableWord_' => array($vendorDir . '/gnugat/PronounceableWord/src'), 'PronounceableWord_' => array($vendorDir . '/gnugat/PronounceableWord/src'),
'PhpImap' => array($vendorDir . '/php-imap/php-imap/src'), 'PhpImap' => array($vendorDir . '/php-imap/php-imap/src'),
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
); );

View file

@ -47,6 +47,24 @@ class ComposerAutoloaderInit125dddd280a32cf75b181166154246ec
$loader->register(true); $loader->register(true);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit125dddd280a32cf75b181166154246ec::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire125dddd280a32cf75b181166154246ec($fileIdentifier, $file);
}
return $loader; return $loader;
} }
} }
function composerRequire125dddd280a32cf75b181166154246ec($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}

View file

@ -6,6 +6,10 @@ namespace Composer\Autoload;
class ComposerStaticInit125dddd280a32cf75b181166154246ec class ComposerStaticInit125dddd280a32cf75b181166154246ec
{ {
public static $files = array (
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
);
public static $prefixesPsr0 = array ( public static $prefixesPsr0 = array (
'P' => 'P' =>
array ( array (
@ -18,6 +22,13 @@ class ComposerStaticInit125dddd280a32cf75b181166154246ec
0 => __DIR__ . '/..' . '/php-imap/php-imap/src', 0 => __DIR__ . '/..' . '/php-imap/php-imap/src',
), ),
), ),
'H' =>
array (
'HTMLPurifier' =>
array (
0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library',
),
),
); );
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)

View file

@ -87,5 +87,54 @@
"word" "word"
], ],
"abandoned": true "abandoned": true
},
{
"name": "ezyang/htmlpurifier",
"version": "v4.9.3",
"version_normalized": "4.9.3.0",
"source": {
"type": "git",
"url": "https://github.com/ezyang/htmlpurifier.git",
"reference": "95e1bae3182efc0f3422896a3236e991049dac69"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/95e1bae3182efc0f3422896a3236e991049dac69",
"reference": "95e1bae3182efc0f3422896a3236e991049dac69",
"shasum": ""
},
"require": {
"php": ">=5.2"
},
"require-dev": {
"simpletest/simpletest": "^1.1"
},
"time": "2017-06-03 02:28:16",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"HTMLPurifier": "library/"
},
"files": [
"library/HTMLPurifier.composer.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL"
],
"authors": [
{
"name": "Edward Z. Yang",
"email": "admin@htmlpurifier.org",
"homepage": "http://ezyang.com"
}
],
"description": "Standards compliant HTML filter written in PHP",
"homepage": "http://htmlpurifier.org/",
"keywords": [
"html"
]
} }
] ]

View file

@ -155,5 +155,74 @@ 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);
$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 // run on every request
delete_old_messages(); delete_old_messages();

View file

@ -1,6 +1,11 @@
<?php <?php
require_once('backend.php'); require_once('backend.php');
$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: // simple router:
if (isset($_GET['username']) && isset($_GET['domain'])) { if (isset($_GET['username']) && isset($_GET['domain'])) {
$username = filter_input(INPUT_GET, 'username', FILTER_SANITIZE_EMAIL); $username = filter_input(INPUT_GET, 'username', FILTER_SANITIZE_EMAIL);
@ -30,7 +35,6 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
exit(); exit();
} }
$emails = get_emails($address); $emails = get_emails($address);
?> ?>
<html lang="en"> <html lang="en">
@ -38,7 +42,7 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
<meta charset="utf-8"> <meta charset="utf-8">
<title><?php echo $address ?></title> <title><?php echo $address ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.gif">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="apple-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"> <meta name="apple-mobile-web-app-status-bar-style" content="black">
@ -77,7 +81,24 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
setInterval(function () { setInterval(function () {
reloadWithTurbolinks(); reloadWithTurbolinks();
}, 15000) }, 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 = '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 = 'block';
document.getElementById('show-plain-button-' + id).style.display = 'none';
return false;
}
</script> </script>
</head> </head>
@ -95,11 +116,11 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
<div class="form-group row"> <div class="form-group row">
<div class="col-sm-4"> <div class="col-sm-4">
<input id="username" class="form-control form-control-lg" name="username" <input id="username" class="form-control form-control-lg" name="username" title="username"
value="<?php echo $username ?>"> value="<?php echo $username ?>">
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<select id="domain" class="form-control form-control-lg" name="domain"> <select id="domain" class="form-control form-control-lg" name="domain" title="domain">
<?php <?php
foreach ($config['domains'] as $domain) { foreach ($config['domains'] as $domain) {
$selected = $domain === $userDomain ? ' selected ' : ''; $selected = $domain === $userDomain ? ' selected ' : '';
@ -166,9 +187,18 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
<div class="col-sm-4 text-right"> <div class="col-sm-4 text-right">
<form class="form-inline float-xs-right"> <form class="form-inline float-xs-right">
<!-- TODO: switch between html and plaintext --> <button type="button" class="btn btn-outline-info btn-sm"
<!-- <button class="btn btn-outline-info btn-sm">show html--> style="display: block"
<!-- </button>--> 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" <a class="btn btn-sm btn-outline-primary " download="true"
role="button" role="button"
@ -216,17 +246,21 @@ if (isset($_GET['username']) && isset($_GET['domain'])) {
<div class="mt-2 card-text"> <div class="mt-2 card-text">
<!-- TODO: switch between html and plaintext --> <!-- show plaintext or html -->
<div> <div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-plain"
<!-- TODO: applyAutolink style="display: block;">
TODO: applyNewlines -->
<?php $text = filter_var($email->textPlain, FILTER_SANITIZE_SPECIAL_CHARS); <?php $text = filter_var($email->textPlain, FILTER_SANITIZE_SPECIAL_CHARS);
echo str_replace('&#10;', '<br />', $text); // Keep newlines
$text = str_replace('&#10;', '<br />', $text);
echo \AutoLinkExtension::auto_link_text($text)
?> ?>
</div> </div>
<div *ngIf="htmlTabActive"> <div id="email-<?php echo filter_var($email->id, FILTER_VALIDATE_INT); ?>-html"
<!-- TODO: stripHtml(mail.textHtml) --> style="display: none;">
<?php
$clean_html = $purifier->purify($email->textHtml);
echo $clean_html;
?>
</div> </div>
</div> </div>