ZeroBin 0.17

* added deletion link.
* small refactoring.
* improved regex checks.
* larger server alt on installation.
This commit is contained in:
Sebastien SAUVAGE 2013-11-01 01:15:14 +01:00 committed by Simon Rupf
parent 6c7de8aca8
commit 5b253cf77c
11 changed files with 217 additions and 104 deletions

View file

@ -5,7 +5,7 @@
; @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin ; @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
; @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) ; @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
; @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License ; @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
; @version 0.15 ; @version 0.17
[main] [main]
; enable or disable discussions ; enable or disable discussions

View file

@ -1,6 +1,5 @@
/* ZeroBin 0.15 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */ /* ZeroBin 0.17 - http://sebsauvage.net/wiki/doku.php?id=php:zerobin */
/* Hé, t'as vu Idleman, j'ai fait un effort sur les CSS ! ;-) */
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. /* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
Licensed under the BSD License. - http://yuilibrary.com/license/ */ Licensed under the BSD License. - http://yuilibrary.com/license/ */
@ -100,8 +99,7 @@ h3 {
padding: 5px 10px; padding: 5px 10px;
} }
#pasteresult {
#pastelink {
background-color: #1F2833; background-color: #1F2833;
color: #fff; color: #fff;
padding: 4px 12px; padding: 4px 12px;
@ -111,9 +109,11 @@ h3 {
box-shadow: inset 0 2px 2px #000; box-shadow: inset 0 2px 2px #000;
} }
#pastelink a { color: #fff; } #pasteresult a { color: #fff; }
#pastelink button { margin-left: 11px } #pasteresult button { margin-left: 11px }
#deletelink { float: right; }
#toolbar, #status { margin-bottom: 5px; } #toolbar, #status { margin-bottom: 5px; }

View file

@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin * @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.15 * @version 0.17
*/ */
// change this, if your php files and data is outside of your webservers document root // change this, if your php files and data is outside of your webservers document root

View file

@ -6,7 +6,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin * @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.15 * @version 0.17
*/ */
// Immediately start random number generator collector. // Immediately start random number generator collector.
@ -328,8 +328,13 @@ function send_data() {
if (data.status == 0) { if (data.status == 0) {
stateExistingPaste(); stateExistingPaste();
var url = scriptLocation() + "?" + data.id + '#' + randomkey; var url = scriptLocation() + "?" + data.id + '#' + randomkey;
var deleteUrl = scriptLocation() + "?pasteid=" + data.id + '&deletetoken=' + data.deletetoken;
showStatus(''); showStatus('');
$('div#pastelink').html('Your paste is <a href="' + url + '">' + url + '</a>').removeClass('hidden');
$('div#pastelink').html('Your paste is <a href="' + url + '">' + url + '</a>');
$('div#deletelink').html('<a href="' + deleteUrl + '">Delete link</a>');
$('div#pasteresult').show();
setElementText($('div#cleartext'), $('textarea#message').val()); setElementText($('div#cleartext'), $('textarea#message').val());
setElementText($('pre#prettyprint'), $('textarea#message').val()); setElementText($('pre#prettyprint'), $('textarea#message').val());
urls2links($('div#cleartext')); urls2links($('div#cleartext'));
@ -357,7 +362,7 @@ function stateNewPaste() {
$('input#password').addClass('hidden'); //$('#password').removeClass('hidden'); $('input#password').addClass('hidden'); //$('#password').removeClass('hidden');
$('div#opendisc').removeClass('hidden'); $('div#opendisc').removeClass('hidden');
$('button#newbutton').removeClass('hidden'); $('button#newbutton').removeClass('hidden');
$('div#pastelink').addClass('hidden'); $('div#pasteresult').addClass('hidden');
$('textarea#message').text(''); $('textarea#message').text('');
$('textarea#message').removeClass('hidden'); $('textarea#message').removeClass('hidden');
$('div#cleartext').addClass('hidden'); $('div#cleartext').addClass('hidden');
@ -385,7 +390,7 @@ function stateExistingPaste() {
$('input#password').addClass('hidden'); $('input#password').addClass('hidden');
$('div#opendisc').addClass('hidden'); $('div#opendisc').addClass('hidden');
$('button#newbutton').removeClass('hidden'); $('button#newbutton').removeClass('hidden');
$('div#pastelink').addClass('hidden'); $('div#pasteresult').addClass('hidden');
$('textarea#message').addClass('hidden'); $('textarea#message').addClass('hidden');
$('div#cleartext').addClass('hidden'); $('div#cleartext').addClass('hidden');
$('div#prettymessage').removeClass('hidden'); $('div#prettymessage').removeClass('hidden');
@ -505,6 +510,14 @@ $(function() {
} }
}); });
// Display status returned by php code if any (eg. Paste was properly deleted.)
if ($('div#status').text().length > 0) {
showStatus($('div#status').text(),false);
return;
}
$('div#status').html(' '); // Keep line height even if content empty.
// Display an existing paste // Display an existing paste
if ($('div#cipherdata').text().length > 1) { if ($('div#cipherdata').text().length > 1) {
// Missing decryption key in URL ? // Missing decryption key in URL ?

71
lib/serversalt.php Normal file
View file

@ -0,0 +1,71 @@
<?php
/**
* ZeroBin
*
* a zero-knowledge paste bin
*
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.17
*/
/**
* serversalt
*
* This is a random string which is unique to each ZeroBin installation.
* It is automatically created if not present.
*
* Salt is used:
* - to generate unique VizHash in discussions (which are not reproductible across ZeroBin servers)
* - to generate unique deletion token (which are not re-usable across ZeroBin servers)
*/
class serversalt extends persistence
{
/**
* @access private
* @static
* @var string
*/
private static $_salt = '';
/**
* generate a large random hexadecimal salt
*
* @access public
* @static
* @return string
*/
public static function generate()
{
$randomSalt = '';
for($i=0; $i<16; ++$i) {
$randomSalt .= base_convert(mt_rand(), 10, 16);
}
self::$_salt = $randomSalt;
return self::$_salt;
}
/**
* get server salt
*
* @access public
* @static
* @return string
*/
public static function get()
{
if (strlen(self::$_salt)) return self::$_salt;
$file = 'salt.php';
if (!self::_exists($file)) {
self::_store(
$file,
'<?php /* |'. self::generate() . '| */ ?>'
);
}
$items = explode('|', file_get_contents(self::getPath($file)));
self::$_salt = $items[1];
return $items[1];
}
}

View file

@ -7,15 +7,15 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin * @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.15 * @version 0.17
*/ */
/** /**
* traffic_limiter * trafficlimiter
* *
* Handles traffic limiting, so no user does more than one call per 10 seconds. * Handles traffic limiting, so no user does more than one call per 10 seconds.
*/ */
class trafficlimiter class trafficlimiter extends persistence
{ {
/** /**
* @access private * @access private
@ -24,13 +24,6 @@ class trafficlimiter
*/ */
private static $_limit = 10; private static $_limit = 10;
/**
* @access private
* @static
* @var string
*/
private static $_path = 'data';
/** /**
* set the time limit in seconds * set the time limit in seconds
* *
@ -44,19 +37,6 @@ class trafficlimiter
self::$_limit = $limit; self::$_limit = $limit;
} }
/**
* set the path
*
* @access public
* @static
* @param string $path
* @return void
*/
public static function setPath($path)
{
self::$_path = $path;
}
/** /**
* traffic limiter * traffic limiter
* *
@ -72,29 +52,18 @@ class trafficlimiter
// disable limits if set to less then 1 // disable limits if set to less then 1
if (self::$_limit < 1) return true; if (self::$_limit < 1) return true;
// Create storage directory if it does not exist. $file = 'traffic_limiter.php';
if (!is_dir(self::$_path)) mkdir(self::$_path, 0705); if (!self::_exists($file))
// Create .htaccess file if it does not exist.
if (!is_file(self::$_path . '/.htaccess'))
{ {
file_put_contents( self::_store(
self::$_path . '/.htaccess',
'Allow from none' . PHP_EOL .
'Deny from all'. PHP_EOL
);
}
$file = self::$_path . '/traffic_limiter.php';
if (!is_file($file))
{
file_put_contents(
$file, $file,
'<?php' . PHP_EOL . '<?php' . PHP_EOL .
'$GLOBALS[\'traffic_limiter\'] = array();' . PHP_EOL '$GLOBALS[\'traffic_limiter\'] = array();' . PHP_EOL
); );
chmod($file, 0705);
} }
require $file; $path = self::getPath($file);
require $path;
$now = time(); $now = time();
$tl = $GLOBALS['traffic_limiter']; $tl = $GLOBALS['traffic_limiter'];
@ -114,7 +83,7 @@ class trafficlimiter
$tl[$ip] = time(); $tl[$ip] = time();
$result = true; $result = true;
} }
file_put_contents( self::_store(
$file, $file,
'<?php' . PHP_EOL . '<?php' . PHP_EOL .
'$GLOBALS[\'traffic_limiter\'] = ' . '$GLOBALS[\'traffic_limiter\'] = ' .

View file

@ -1,16 +1,27 @@
<?php <?php
// VizHash_GD 0.0.4 beta ZeroBin 0.15 /**
// Visual Hash implementation in php4+GD, stripped down and modified version for ZeroBin * VizHash_GD
// See: http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd *
// This is free software under the zlib/libpng licence * Visual Hash implementation in php4+GD,
// http://www.opensource.org/licenses/zlib-license.php * stripped down and modified version for ZeroBin
/* Example: *
$vz = new vizhash16x16(); * @link http://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
$data = $vz->generate('hello'); * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
header('Content-type: image/png'); * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
echo $data; * @version 0.0.4 beta ZeroBin 0.17
exit; */
*/
/**
* vizhash16x16
*
* Example:
* $vz = new vizhash16x16();
* $data = $vz->generate('hello');
* header('Content-type: image/png');
* echo $data;
* exit;
*/
class vizhash16x16 class vizhash16x16
{ {
private $VALUES; private $VALUES;
@ -22,15 +33,7 @@ class vizhash16x16
{ {
$this->width=16; $this->width=16;
$this->height=16; $this->height=16;
$this->salt = serversalt::get();
// Read salt from file (and create it if does not exist).
// The salt will make vizhash avatar unique on each ZeroBin installation
// to prevent IP checking.
$saltfile = PATH . 'data/salt.php';
if (!is_file($saltfile))
file_put_contents($saltfile,'<?php /* |'.$this->randomSalt().'| */ ?>');
$items=explode('|',file_get_contents($saltfile));
$this->salt = $items[1];
} }
// Generate a 16x16 png corresponding to $text. // Generate a 16x16 png corresponding to $text.

View file

@ -7,7 +7,7 @@
* @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin * @link http://sebsauvage.net/wiki/doku.php?id=php:zerobin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net) * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License * @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.15 * @version 0.17
*/ */
/** /**
@ -20,7 +20,7 @@ class zerobin
/* /*
* @const string version * @const string version
*/ */
const VERSION = 'Alpha 0.15'; const VERSION = 'Alpha 0.17';
/** /**
* @access private * @access private
@ -42,6 +42,12 @@ class zerobin
*/ */
private $_error = ''; private $_error = '';
/**
* @access private
* @var string
*/
private $_status = '';
/** /**
* @access private * @access private
* @var zerobin_data * @var zerobin_data
@ -60,7 +66,7 @@ class zerobin
if (version_compare(PHP_VERSION, '5.2.6') < 0) if (version_compare(PHP_VERSION, '5.2.6') < 0)
die('ZeroBin requires php 5.2.6 or above to work. Sorry.'); die('ZeroBin requires php 5.2.6 or above to work. Sorry.');
// In case stupid admin has left magic_quotes enabled in php.ini. // in case stupid admin has left magic_quotes enabled in php.ini
if (get_magic_quotes_gpc()) if (get_magic_quotes_gpc())
{ {
$_POST = array_map('filter::stripslashes_deep', $_POST); $_POST = array_map('filter::stripslashes_deep', $_POST);
@ -68,21 +74,26 @@ class zerobin
$_COOKIE = array_map('filter::stripslashes_deep', $_COOKIE); $_COOKIE = array_map('filter::stripslashes_deep', $_COOKIE);
} }
// Load config from ini file. // load config from ini file
$this->_init(); $this->_init();
// Create new paste or comment. // create new paste or comment
if (!empty($_POST['data'])) if (!empty($_POST['data']))
{ {
$this->_create(); $this->_create($_POST['data']);
} }
// Display an existing paste. // delete an existing paste
elseif (!empty($_GET['deletetoken']) && !empty($_GET['pasteid']))
{
$this->_delete($_GET['pasteid'], $_GET['deletetoken']);
}
// display an existing paste
elseif (!empty($_SERVER['QUERY_STRING'])) elseif (!empty($_SERVER['QUERY_STRING']))
{ {
$this->_read(); $this->_read($_SERVER['QUERY_STRING']);
} }
// Display ZeroBin frontend // display ZeroBin frontend
$this->_view(); $this->_view();
} }
@ -126,7 +137,7 @@ class zerobin
} }
/** /**
* Store new paste or comment. * Store new paste or comment
* *
* POST contains: * POST contains:
* data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct) * data (mandatory) = json encoded SJCL encrypted text (containing keys: iv,salt,ct)
@ -139,9 +150,10 @@ class zerobin
* pasteid (optional) = in discussion, which paste this comment belongs to. * pasteid (optional) = in discussion, which paste this comment belongs to.
* *
* @access private * @access private
* @param string $data
* @return void * @return void
*/ */
private function _create() private function _create($data)
{ {
header('Content-type: application/json'); header('Content-type: application/json');
$error = false; $error = false;
@ -159,7 +171,6 @@ class zerobin
); );
// Make sure content is not too big. // Make sure content is not too big.
$data = $_POST['data'];
if ( if (
strlen($data) > $this->_conf['main']['sizelimit'] strlen($data) > $this->_conf['main']['sizelimit']
) $this->_return_message( ) $this->_return_message(
@ -252,8 +263,8 @@ class zerobin
$pasteid = $_POST['pasteid']; $pasteid = $_POST['pasteid'];
$parentid = $_POST['parentid']; $parentid = $_POST['parentid'];
if ( if (
!preg_match('/[a-f\d]{16}/', $pasteid) || !preg_match('/\A[a-f\d]{16}\z/', $pasteid) ||
!preg_match('/[a-f\d]{16}/', $parentid) !preg_match('/\A[a-f\d]{16}\z/', $parentid)
) $this->_return_message(1, 'Invalid data.'); ) $this->_return_message(1, 'Invalid data.');
// Comments do not expire (it's the paste that expires) // Comments do not expire (it's the paste that expires)
@ -297,23 +308,60 @@ class zerobin
$this->_model()->create($dataid, $storage) === false $this->_model()->create($dataid, $storage) === false
) $this->_return_message(1, 'Error saving paste. Sorry.'); ) $this->_return_message(1, 'Error saving paste. Sorry.');
// Generate the "delete" token.
// The token is the hmac of the pasteid signed with the server salt.
// The paste can be delete by calling http://myserver.com/zerobin/?pasteid=<pasteid>&deletetoken=<deletetoken>
$deletetoken = hash_hmac('sha1', $dataid , serversalt::get());
// 0 = no error // 0 = no error
$this->_return_message(0, $dataid); $this->_return_message(0, $dataid, array('deletetoken' => $deletetoken));
} }
$this->_return_message(1, 'Server error.'); $this->_return_message(1, 'Server error.');
} }
/** /**
* Read an existing paste or comment. * Delete an existing paste
* *
* @access private * @access private
* @param string $dataid
* @param string $deletetoken
* @return void * @return void
*/ */
private function _read() private function _delete($dataid, $deletetoken)
{ {
$dataid = $_SERVER['QUERY_STRING']; // Is this a valid paste identifier?
if (preg_match('\A[a-f\d]{16}\z', $dataid))
{
// Check that paste exists.
if (!$this->_model()->exists($dataid))
{
$this->_error = 'Paste does not exist, has expired or has been deleted.';
return;
}
}
// Make sure token is valid.
if ($deletetoken != hash_hmac('sha1', $dataid , serversalt::get()))
{
$this->_error = 'Wrong deletion token. Paste was not deleted.';
return;
}
// Paste exists and deletion token is valid: Delete the paste.
$this->_model()->delete($dataid);
$this->_status = 'Paste was properly deleted.';
}
/**
* Read an existing paste or comment
*
* @access private
* @param string $dataid
* @return void
*/
private function _read($dataid)
{
// Is this a valid paste identifier? // Is this a valid paste identifier?
if (preg_match('\A[a-f\d]{16}\z', $dataid)) if (preg_match('\A[a-f\d]{16}\z', $dataid))
{ {
@ -331,7 +379,7 @@ class zerobin
{ {
// Delete the paste // Delete the paste
$this->_model()->delete($dataid); $this->_model()->delete($dataid);
$this->_error = 'Paste does not exist or has expired.'; $this->_error = 'Paste does not exist, has expired or has been deleted.';
} }
// If no error, return the paste. // If no error, return the paste.
else else
@ -398,7 +446,8 @@ class zerobin
$page = new RainTPL; $page = new RainTPL;
// we escape it here because ENT_NOQUOTES can't be used in RainTPL templates // we escape it here because ENT_NOQUOTES can't be used in RainTPL templates
$page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES)); $page->assign('CIPHERDATA', htmlspecialchars($this->_data, ENT_NOQUOTES));
$page->assign('ERRORMESSAGE', $this->_error); $page->assign('ERROR', $this->_error);
$page->assign('STATUS', $this->_status);
$page->assign('VERSION', self::VERSION); $page->assign('VERSION', self::VERSION);
$page->assign('BURNAFTERREADINGSELECTED', $this->_conf['main']['burnafterreadingselected']); $page->assign('BURNAFTERREADINGSELECTED', $this->_conf['main']['burnafterreadingselected']);
$page->assign('OPENDISCUSSION', $this->_conf['main']['opendiscussion']); $page->assign('OPENDISCUSSION', $this->_conf['main']['opendiscussion']);
@ -414,9 +463,10 @@ class zerobin
* @access private * @access private
* @param bool $status * @param bool $status
* @param string $message * @param string $message
* @param array $other
* @return void * @return void
*/ */
private function _return_message($status, $message) private function _return_message($status, $message, $other = array())
{ {
$result = array('status' => $status); $result = array('status' => $status);
if ($status) if ($status)
@ -427,6 +477,7 @@ class zerobin
{ {
$result['id'] = $message; $result['id'] = $message;
} }
$result += $other;
exit(json_encode($result)); exit(json_encode($result));
} }
} }

View file

@ -43,8 +43,8 @@
</header> </header>
<section> <section>
<article> <article>
<div id="status"> </div> <div id="status">{$STATUS|htmlspecialchars}</div>
<div id="errormessage" class="hidden">{$ERRORMESSAGE|htmlspecialchars}</div> <div id="errormessage" class="hidden">{$ERROR|htmlspecialchars}</div>
<div id="toolbar"> <div id="toolbar">
<button id="newbutton" onclick="window.location.href=scriptLocation();return false;" class="hidden"><img src="img/icon_new.png#" width="11" height="15" alt="" />New</button> <button id="newbutton" onclick="window.location.href=scriptLocation();return false;" class="hidden"><img src="img/icon_new.png#" width="11" height="15" alt="" />New</button>
<button id="sendbutton" onclick="send_data();return false;" class="hidden"><img src="img/icon_send.png#" width="18" height="15" alt="" />Send</button> <button id="sendbutton" onclick="send_data();return false;" class="hidden"><img src="img/icon_send.png#" width="18" height="15" alt="" />Send</button>
@ -70,7 +70,10 @@
<label for="opendiscussion">Open discussion</label> <label for="opendiscussion">Open discussion</label>
</div> </div>
</div> </div>
<div id="pastelink" class="hidden"></div> <div id="pasteresult" style="display:none;">
<div id="deletelink"></div>
<div id="pastelink"></div>
</div>
<div id="prettymessage" class="hidden"> <div id="prettymessage" class="hidden">
<pre id="prettyprint" class="prettyprint linenums:1"></pre> <pre id="prettyprint" class="prettyprint linenums:1"></pre>
</div> </div>

View file

@ -5,6 +5,8 @@ class RainTPLTest extends PHPUnit_Framework_TestCase
private static $error = 'foo bar'; private static $error = 'foo bar';
private static $status = '!*#@?$+';
private static $expire = array( private static $expire = array(
'5min' => '5 minutes', '5min' => '5 minutes',
'1hour' => '1 hour', '1hour' => '1 hour',
@ -26,7 +28,8 @@ class RainTPLTest extends PHPUnit_Framework_TestCase
$page = new RainTPL; $page = new RainTPL;
// We escape it here because ENT_NOQUOTES can't be used in RainTPL templates. // We escape it here because ENT_NOQUOTES can't be used in RainTPL templates.
$page->assign('CIPHERDATA', htmlspecialchars(self::$data, ENT_NOQUOTES)); $page->assign('CIPHERDATA', htmlspecialchars(self::$data, ENT_NOQUOTES));
$page->assign('ERRORMESSAGE', self::$error); $page->assign('ERROR', self::$error);
$page->assign('STATUS', self::$status);
$page->assign('VERSION', self::$version); $page->assign('VERSION', self::$version);
$page->assign('BURNAFTERREADINGSELECTED', false); $page->assign('BURNAFTERREADINGSELECTED', false);
$page->assign('OPENDISCUSSION', false); $page->assign('OPENDISCUSSION', false);

View file

@ -6,14 +6,14 @@ class trafficlimiterTest extends PHPUnit_Framework_TestCase
public function setUp() public function setUp()
{ {
/* Setup Routine */ /* Setup Routine */
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit' . DIRECTORY_SEPARATOR; $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit';
trafficlimiter::setPath($this->_path); trafficlimiter::setPath($this->_path);
} }
public function tearDown() public function tearDown()
{ {
/* Tear Down Routine */ /* Tear Down Routine */
helper::rmdir($this->_path); helper::rmdir($this->_path . DIRECTORY_SEPARATOR);
} }
public function testTrafficGetsLimited() public function testTrafficGetsLimited()