Merge pull request #59 from PrivateBin/52-identicons

Implementation of Identicons library
This commit is contained in:
El RIDO
2016-08-12 12:22:20 +02:00
committed by GitHub
25 changed files with 1700 additions and 138 deletions

View File

@@ -50,8 +50,8 @@ class Configuration
'languageselection' => false,
'languagedefault' => '',
'urlshortener' => '',
'vizhash' => true,
'cspheader' => 'default-src \'none\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\';',
'icon' => 'identicon',
'cspheader' => 'default-src \'none\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:;',
'zerobincompatibility' => false,
),
'expire' => array(

View File

@@ -10,11 +10,12 @@
* @version 0.22
*/
namespace PrivateBin\model;
namespace PrivateBin\Model;
use PrivateBin\Sjcl;
use PrivateBin\Persistence\TrafficLimiter;
use PrivateBin\Vizhash16x16;
use Identicon\Identicon;
use Exception;
/**
@@ -192,17 +193,26 @@ class Comment extends AbstractModel
}
$this->_data->meta->nickname = $nickname;
if ($this->_conf->getKey('vizhash')) {
// Generation of the anonymous avatar (Vizhash):
// If a nickname is provided, we generate a Vizhash.
// (We assume that if the user did not enter a nickname, he/she wants
// to be anonymous and we will not generate the vizhash.)
$vh = new Vizhash16x16();
$pngdata = $vh->generate(TrafficLimiter::getIp());
if ($pngdata != '') {
$this->_data->meta->vizhash = 'data:image/png;base64,' . base64_encode($pngdata);
// If a nickname is provided, we generate an icon based on a SHA512 HMAC
// of the users IP. (We assume that if the user did not enter a nickname,
// the user wants to be anonymous and we will not generate an icon.)
$icon = $this->_conf->getKey('icon');
if ($icon != 'none') {
$pngdata = '';
$hmac = TrafficLimiter::getHash();
if ($icon == 'identicon') {
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri($hmac, 16);
} elseif ($icon == 'vizhash') {
$vh = new Vizhash16x16();
$pngdata = 'data:image/png;base64,' . base64_encode(
$vh->generate($hmac)
);
}
if ($pngdata != '') {
$this->_data->meta->vizhash = $pngdata;
}
// Once the avatar is generated, we do not keep the IP address, nor its hash.
}
// Once the icon is generated, we do not keep the IP address hash.
}
}

View File

@@ -49,7 +49,6 @@ class ServerSalt extends AbstractPersistence
$randomSalt = bin2hex(mcrypt_create_iv(256, MCRYPT_DEV_URANDOM));
} else {
// fallback to mt_rand()
for ($i = 0; $i < 256; ++$i) {
$randomSalt .= base_convert(mt_rand(), 10, 16);
}

View File

@@ -73,15 +73,16 @@ class TrafficLimiter extends AbstractPersistence
}
/**
* get the current visitors IP address
* get a HMAC of the current visitors IP address
*
* @access public
* @static
* @param string $algo
* @return string
*/
public static function getIp()
public static function getHash($algo = 'sha512')
{
return $_SERVER[self::$_ipKey];
return hash_hmac($algo, $_SERVER[self::$_ipKey], ServerSalt::get());
}
/**
@@ -101,8 +102,6 @@ class TrafficLimiter extends AbstractPersistence
return true;
}
$ip = hash_hmac('sha256', self::getIp(), ServerSalt::get());
$file = 'traffic_limiter.php';
if (!self::_exists($file)) {
self::_store(
@@ -117,17 +116,19 @@ class TrafficLimiter extends AbstractPersistence
$now = time();
$tl = $GLOBALS['traffic_limiter'];
// purge file of expired IPs to keep it small
// purge file of expired hashes to keep it small
foreach ($tl as $key => $time) {
if ($time + self::$_limit < $now) {
unset($tl[$key]);
}
}
if (array_key_exists($ip, $tl) && ($tl[$ip] + self::$_limit >= $now)) {
// this hash is used as an array key, hence a shorter hash is used
$hash = self::getHash('sha256');
if (array_key_exists($hash, $tl) && ($tl[$hash] + self::$_limit >= $now)) {
$result = false;
} else {
$tl[$ip] = time();
$tl[$hash] = time();
$result = true;
}
self::_store(

View File

@@ -11,6 +11,7 @@
*/
namespace PrivateBin;
use Exception;
/**

View File

@@ -13,8 +13,6 @@
namespace PrivateBin;
use PrivateBin\Persistence\ServerSalt;
/**
* Vizhash16x16
*
@@ -60,14 +58,6 @@ class Vizhash16x16
*/
private $height;
/**
* salt used when generating the image
*
* @access private
* @var string
*/
private $salt;
/**
* constructor
*
@@ -78,12 +68,13 @@ class Vizhash16x16
{
$this->width = 16;
$this->height = 16;
$this->salt = ServerSalt::get();
}
/**
* Generate a 16x16 png corresponding to $text.
*
* The given text should to be 128 to 150 characters long
*
* @access public
* @param string $text
* @return string PNG data. Or empty string if GD is not available.
@@ -94,44 +85,35 @@ class Vizhash16x16
return '';
}
// We hash the input string.
$hash=hash('sha1', $text.$this->salt).hash('md5', $text.$this->salt);
$hash=$hash.strrev($hash); # more data to make graphics
$hashlen=strlen($hash);
$textlen = strlen($text);
// We convert the hash into an array of integers.
$this->VALUES=array();
for ($i=0; $i<$hashlen; $i=$i+2) {
array_push($this->VALUES, hexdec(substr($hash, $i, 2)));
$this->VALUES = array();
for ($i = 0; $i < $textlen; $i = $i + 2) {
array_push($this->VALUES, hexdec(substr($text, $i, 2)));
}
$this->VALUES_INDEX=0; // to walk the array.
$this->VALUES_INDEX = 0; // to walk the array.
// Then use these integers to drive the creation of an image.
$image = imagecreatetruecolor($this->width, $this->height);
$r0 = $this->getInt();
$r=$r0;
$g0 = $this->getInt();
$g=$g0;
$b0 = $this->getInt();
$b=$b0;
$r = $r0 = $this->getInt();
$g = $g0 = $this->getInt();
$b = $b0 = $this->getInt();
// First, create an image with a specific gradient background.
$op='v';
if (($this->getInt()%2)==0) {
$op='h';
$op = 'v';
if (($this->getInt() % 2) == 0) {
$op = 'h';
};
$image = $this->degrade($image, $op, array($r0, $g0, $b0), array(0, 0, 0));
for ($i=0; $i<7; $i=$i+1) {
$action=$this->getInt();
for ($i = 0; $i < 7; ++$i) {
$action = $this->getInt();
$color = imagecolorallocate($image, $r, $g, $b);
$r = ($r0 + $this->getInt()/25)%256;
$g = ($g0 + $this->getInt()/25)%256;
$b = ($b0 + $this->getInt()/25)%256;
$r0=$r;
$g0=$g;
$b0=$b;
$r = $r0 = ($r0 + $this->getInt() / 25) % 256;
$g = $g0 = ($g0 + $this->getInt() / 25) % 256;
$b = $b0 = ($b0 + $this->getInt() / 25) % 256;
$this->drawshape($image, $action, $color);
}
@@ -154,8 +136,8 @@ class Vizhash16x16
*/
private function getInt()
{
$v= $this->VALUES[$this->VALUES_INDEX];
$this->VALUES_INDEX++;
$v = $this->VALUES[$this->VALUES_INDEX];
++$this->VALUES_INDEX;
$this->VALUES_INDEX %= count($this->VALUES); // Warp around the array
return $v;
}
@@ -168,7 +150,7 @@ class Vizhash16x16
*/
private function getX()
{
return $this->width*$this->getInt()/256;
return $this->width * $this->getInt() / 256;
}
/**
@@ -179,7 +161,7 @@ class Vizhash16x16
*/
private function getY()
{
return $this->height*$this->getInt()/256;
return $this->height * $this->getInt() / 256;
}
/**
@@ -197,7 +179,7 @@ class Vizhash16x16
*/
private function degrade($img, $direction, $color1, $color2)
{
if ($direction=='h') {
if ($direction == 'h') {
$size = imagesx($img);
$sizeinv = imagesy($img);
} else {
@@ -205,15 +187,15 @@ class Vizhash16x16
$sizeinv = imagesx($img);
}
$diffs = array(
(($color2[0]-$color1[0])/$size),
(($color2[1]-$color1[1])/$size),
(($color2[2]-$color1[2])/$size)
);
for ($i=0;$i<$size;$i++) {
$r = $color1[0]+($diffs[0]*$i);
$g = $color1[1]+($diffs[1]*$i);
$b = $color1[2]+($diffs[2]*$i);
if ($direction=='h') {
(($color2[0] - $color1[0]) / $size),
(($color2[1] - $color1[1]) / $size),
(($color2[2] - $color1[2]) / $size)
);
for ($i = 0; $i < $size; ++$i) {
$r = $color1[0] + ($diffs[0] * $i);
$g = $color1[1] + ($diffs[1] * $i);
$b = $color1[2] + ($diffs[2] * $i);
if ($direction == 'h') {
imageline($img, $i, 0, $i, $sizeinv, imagecolorallocate($img, $r, $g, $b));
} else {
imageline($img, 0, $i, $sizeinv, $i, imagecolorallocate($img, $r, $g, $b));
@@ -233,7 +215,7 @@ class Vizhash16x16
*/
private function drawshape($image, $action, $color)
{
switch ($action%7) {
switch ($action % 7) {
case 0:
ImageFilledRectangle($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
break;
@@ -242,11 +224,12 @@ class Vizhash16x16
ImageFilledEllipse($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
break;
case 3:
$points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(),$this->getX(), $this->getY());
$points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY());
ImageFilledPolygon($image, $points, 4, $color);
break;
default:
$start=$this->getInt()*360/256; $end=$start+$this->getInt()*180/256;
$start = $this->getInt() * 360 /256;
$end = $start + $this->getInt() * 180 / 256;
ImageFilledArc($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $start, $end, $color, IMG_ARC_PIE);
}
}