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
commit 0a628e83c1
25 changed files with 1700 additions and 138 deletions

11
.gitignore vendored
View File

@ -1,15 +1,12 @@
# Ignore data/, tmp/ and vendor/
data/
!lib/data/
tmp/
vendor/
# Ignore for safety # Ignore for safety
.htaccess .htaccess
.htpasswd .htpasswd
# Ignore data/ and vendor/
data/
vendor/
# Ignore unit testing logs, api docs and eclipse project files # Ignore unit testing logs, api docs and eclipse project files
tst/log/
doc/ doc/
composer.lock tst/log/
.settings .settings
.buildpath .buildpath
.project .project

View File

@ -5,7 +5,7 @@
* ADDED: re-introduced URL shortener support (optional), which was removed back in version 0.16 for privacy concerns * ADDED: re-introduced URL shortener support (optional), which was removed back in version 0.16 for privacy concerns
* ADDED: Preview tab, helpful for writing markdown code or check source code rendering * ADDED: Preview tab, helpful for writing markdown code or check source code rendering
* ADDED: Automatic purging of expired pastes, done on paste creation * ADDED: Automatic purging of expired pastes, done on paste creation
* ADDED: Option to disable vizhashs in discussions (will only affect newly created pastes) * ADDED: Option to disable icons in discussions (will only affect newly created pastes)
* ADDED: Composer support * ADDED: Composer support
* CHANGED: Renamed the ZeroBin fork to PrivateBin * CHANGED: Renamed the ZeroBin fork to PrivateBin
* CHANGED: Removed unmaintained RainTPL template engine, replacing the templates with straight forward PHP files * CHANGED: Removed unmaintained RainTPL template engine, replacing the templates with straight forward PHP files
@ -14,7 +14,9 @@
* CHANGED: Switched to GCM instead CCM mode for AES encryption for newly created pastes * CHANGED: Switched to GCM instead CCM mode for AES encryption for newly created pastes
* CHANGED: Switched to a SHA256 HMAC of the IP in traffic limiter instead of storing it in plain text on the server * CHANGED: Switched to a SHA256 HMAC of the IP in traffic limiter instead of storing it in plain text on the server
* CHANGED: Introduced content security policy header to reduce cross site scripting (XSS) risks * CHANGED: Introduced content security policy header to reduce cross site scripting (XSS) risks
* CHANGED: Refactored PHP code to conform to PSR-4 and PSR-2 standards. * CHANGED: Refactored PHP code to conform to PSR-4 and PSR-2 standards
* CHANGED: Switched to Identicons as the default for comments with nicknames
* CHANGED: Vizhash is now optional and based on (128 byte) SHA512 HMAC instead of (144 bytes) combination of MD5, SHA1 and a reversal of that string
* FIXED: Content-type negociation for HTML in certain uncommon browser configurations * FIXED: Content-type negociation for HTML in certain uncommon browser configurations
* FIXED: JavaScript error displayed before page is loaded or during attachment load * FIXED: JavaScript error displayed before page is loaded or during attachment load
* FIXED: Don't strip space characters at beginning or end of optional password * FIXED: Don't strip space characters at beginning or end of optional password

View File

@ -4,8 +4,9 @@ PrivateBin consists of PHP and JS code which was originally written by Sébastie
Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are
libraries that fall under the GPLv2 (SJCL, rawinflate, rawdeflate), BSD libraries that fall under the GPLv2 (SJCL, rawinflate, rawdeflate), BSD
2-clause (SJCL), BSD 3-clause (base64.js version 2.1.9, Showdown), MIT 2-clause (SJCL), BSD 3-clause (base64.js version 2.1.9, Showdown), MIT
(base64.js version 1.7, Bootstrap), Apache (prettify.js) and CC-BY (favicon, (base64.js version 1.7, Bootstrap, Identicon), Apache (prettify.js) and CC-BY
icon, logo) licenses. All of these license terms can be found here below: (favicon, icon, logo) licenses. All of these license terms can be found here
below:
## Zlib/libpng license for PrivateBin ## Zlib/libpng license for PrivateBin
@ -440,6 +441,28 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
## MIT License for Identicon
Copyright © 2013 Benjamin Laugueux <benjamin@yzalis.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## Apache License for prettify.js ## Apache License for prettify.js
_Version 2.0, January 2004_ _Version 2.0, January 2004_

View File

@ -53,18 +53,19 @@ languageselection = false
; the pastes encryption key ; the pastes encryption key
; urlshortener = "https://shortener.example.com/api?link=" ; urlshortener = "https://shortener.example.com/api?link="
; (optional) vizhash is a weak mechanism to detect if a comment was from a ; (optional) IP based icons are a weak mechanism to detect if a comment was from
; different user when the same username was used in a comment. It is based on ; a different user when the same username was used in a comment. It might be
; the IP and might be used to get the posters IP if the server salt is leaked ; used to get the IP of a non anonymous comment poster if the server salt is
; and a rainbow table is generated for all IPs. Enabled by default. ; leaked and a SHA256 HMAC rainbow table is generated for all (relevant) IPs.
; vizhash = false ; Can be set to one these values: none / vizhash / identicon (default).
; icon = none
; Content Security Policy headers allow a website to restrict what sources are ; Content Security Policy headers allow a website to restrict what sources are
; allowed to be accessed in its context. You need to change this if you added ; allowed to be accessed in its context. You need to change this if you added
; custom scripts from third-party domains to your templates, e.g. tracking ; custom scripts from third-party domains to your templates, e.g. tracking
; scripts or run your site behind certain DDoS-protection services. ; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/ ; Check the documentation at https://content-security-policy.com/
cspheader = "default-src 'none'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self';" cspheader = "default-src 'none'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:;"
; stay compatible with PrivateBin Alpha 0.19, less secure ; stay compatible with PrivateBin Alpha 0.19, less secure
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of

View File

@ -18,7 +18,8 @@
} }
], ],
"require": { "require": {
"php": "^5.2.6 || ^7.0" "php": "^5.3 || ^7.0",
"yzalis/identicon": "^1.1"
}, },
"require-dev": { "require-dev": {
"codacy/coverage": "dev-master", "codacy/coverage": "dev-master",

858
composer.lock generated Normal file
View File

@ -0,0 +1,858 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "e3520dc72004bd92b2bd0b0febf71c7f",
"content-hash": "ac3ea1f44998ea42345107fd21d6a2e0",
"packages": [
{
"name": "yzalis/identicon",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/yzalis/Identicon.git",
"reference": "a99fc2a3d018512f7914bc6f972952536c0f309b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yzalis/Identicon/zipball/a99fc2a3d018512f7914bc6f972952536c0f309b",
"reference": "a99fc2a3d018512f7914bc6f972952536c0f309b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"fzaninotto/faker": "1.2.*@dev"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"autoload": {
"psr-0": {
"Identicon": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Benjamin Laugueux",
"email": "benjamin@yzalis.com"
}
],
"description": "Create awesome unique avatar.",
"homepage": "http://identicon-php.org",
"keywords": [
"avatar",
"identicon",
"image"
],
"time": "2014-07-13 09:19:12"
}
],
"packages-dev": [
{
"name": "codacy/coverage",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/codacy/php-codacy-coverage.git",
"reference": "92194b1ece3379e56bb1f95d6f540fc6244d9946"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codacy/php-codacy-coverage/zipball/92194b1ece3379e56bb1f95d6f540fc6244d9946",
"reference": "92194b1ece3379e56bb1f95d6f540fc6244d9946",
"shasum": ""
},
"require": {
"gitonomy/gitlib": "~0.1",
"php": ">=5.3.3",
"symfony/console": "~2.5|~3.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5"
},
"bin": [
"bin/codacycoverage"
],
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jakob Pupke",
"email": "jakob.pupke@gmail.com"
}
],
"description": "Sends PHP test coverage information to Codacy.",
"homepage": "https://github.com/codacy/php-codacy-coverage",
"time": "2016-07-07 15:33:12"
},
{
"name": "codeclimate/php-test-reporter",
"version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/codeclimate/php-test-reporter.git",
"reference": "68786c391d2b859054046a7b7ed07c64e7b741a1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codeclimate/php-test-reporter/zipball/68786c391d2b859054046a7b7ed07c64e7b741a1",
"reference": "68786c391d2b859054046a7b7ed07c64e7b741a1",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3",
"satooshi/php-coveralls": "^1.0",
"symfony/console": "^2.0|^3.0"
},
"require-dev": {
"ext-xdebug": "*",
"phpunit/phpunit": "3.7.*@stable",
"tm/tooly-composer-script": "^1.0"
},
"bin": [
"composer/bin/test-reporter"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.3.x-dev"
},
"tools": {
"box": {
"url": "https://github.com/box-project/box2/releases/download/2.7.2/box-2.7.2.phar",
"only-dev": true
}
}
},
"autoload": {
"psr-4": {
"CodeClimate\\PhpTestReporter\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Code Climate",
"email": "hello@codeclimate.com",
"homepage": "https://codeclimate.com"
}
],
"description": "PHP client for reporting test coverage to Code Climate",
"homepage": "https://github.com/codeclimate/php-test-reporter",
"keywords": [
"codeclimate",
"coverage"
],
"time": "2016-08-09 19:41:51"
},
{
"name": "gitonomy/gitlib",
"version": "v0.1.8",
"source": {
"type": "git",
"url": "https://github.com/gitonomy/gitlib.git",
"reference": "f575b8f7da917ade7890c6aa705fa22545690389"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/gitonomy/gitlib/zipball/f575b8f7da917ade7890c6aa705fa22545690389",
"reference": "f575b8f7da917ade7890c6aa705fa22545690389",
"shasum": ""
},
"require": {
"symfony/process": "^2.3|^3.0"
},
"require-dev": {
"psr/log": "^1.0"
},
"suggest": {
"psr/log": "Add some log"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"Gitonomy\\Git\\": "src/Gitonomy/Git/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Alexandre Salomé",
"email": "alexandre.salome@gmail.com",
"homepage": "http://alexandre-salome.fr"
},
{
"name": "Julien DIDIER",
"email": "genzo.wm@gmail.com",
"homepage": "http://www.jdidier.net"
}
],
"description": "Library for accessing git",
"homepage": "http://gitonomy.com",
"time": "2015-12-01 22:25:57"
},
{
"name": "guzzle/guzzle",
"version": "v3.9.3",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle3.git",
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle3/zipball/0645b70d953bc1c067bbc8d5bc53194706b628d9",
"reference": "0645b70d953bc1c067bbc8d5bc53194706b628d9",
"shasum": ""
},
"require": {
"ext-curl": "*",
"php": ">=5.3.3",
"symfony/event-dispatcher": "~2.1"
},
"replace": {
"guzzle/batch": "self.version",
"guzzle/cache": "self.version",
"guzzle/common": "self.version",
"guzzle/http": "self.version",
"guzzle/inflection": "self.version",
"guzzle/iterator": "self.version",
"guzzle/log": "self.version",
"guzzle/parser": "self.version",
"guzzle/plugin": "self.version",
"guzzle/plugin-async": "self.version",
"guzzle/plugin-backoff": "self.version",
"guzzle/plugin-cache": "self.version",
"guzzle/plugin-cookie": "self.version",
"guzzle/plugin-curlauth": "self.version",
"guzzle/plugin-error-response": "self.version",
"guzzle/plugin-history": "self.version",
"guzzle/plugin-log": "self.version",
"guzzle/plugin-md5": "self.version",
"guzzle/plugin-mock": "self.version",
"guzzle/plugin-oauth": "self.version",
"guzzle/service": "self.version",
"guzzle/stream": "self.version"
},
"require-dev": {
"doctrine/cache": "~1.3",
"monolog/monolog": "~1.0",
"phpunit/phpunit": "3.7.*",
"psr/log": "~1.0",
"symfony/class-loader": "~2.1",
"zendframework/zend-cache": "2.*,<2.3",
"zendframework/zend-log": "2.*,<2.3"
},
"suggest": {
"guzzlehttp/guzzle": "Guzzle 5 has moved to a new package name. The package you have installed, Guzzle 3, is deprecated."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.9-dev"
}
},
"autoload": {
"psr-0": {
"Guzzle": "src/",
"Guzzle\\Tests": "tests/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
},
{
"name": "Guzzle Community",
"homepage": "https://github.com/guzzle/guzzle/contributors"
}
],
"description": "PHP HTTP client. This library is deprecated in favor of https://packagist.org/packages/guzzlehttp/guzzle",
"homepage": "http://guzzlephp.org/",
"keywords": [
"client",
"curl",
"framework",
"http",
"http client",
"rest",
"web service"
],
"abandoned": "guzzlehttp/guzzle",
"time": "2015-03-18 18:23:50"
},
{
"name": "psr/log",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2012-12-21 11:40:51"
},
{
"name": "satooshi/php-coveralls",
"version": "v1.0.1",
"source": {
"type": "git",
"url": "https://github.com/satooshi/php-coveralls.git",
"reference": "da51d304fe8622bf9a6da39a8446e7afd432115c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/satooshi/php-coveralls/zipball/da51d304fe8622bf9a6da39a8446e7afd432115c",
"reference": "da51d304fe8622bf9a6da39a8446e7afd432115c",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-simplexml": "*",
"guzzle/guzzle": "^2.8|^3.0",
"php": ">=5.3.3",
"psr/log": "^1.0",
"symfony/config": "^2.1|^3.0",
"symfony/console": "^2.1|^3.0",
"symfony/stopwatch": "^2.0|^3.0",
"symfony/yaml": "^2.0|^3.0"
},
"suggest": {
"symfony/http-kernel": "Allows Symfony integration"
},
"bin": [
"bin/coveralls"
],
"type": "library",
"autoload": {
"psr-4": {
"Satooshi\\": "src/Satooshi/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kitamura Satoshi",
"email": "with.no.parachute@gmail.com",
"homepage": "https://www.facebook.com/satooshi.jp"
}
],
"description": "PHP client library for Coveralls API",
"homepage": "https://github.com/satooshi/php-coveralls",
"keywords": [
"ci",
"coverage",
"github",
"test"
],
"time": "2016-01-20 17:35:46"
},
{
"name": "symfony/config",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "a7630397b91be09cdd2fe57fd13612e258700598"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/a7630397b91be09cdd2fe57fd13612e258700598",
"reference": "a7630397b91be09cdd2fe57fd13612e258700598",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/filesystem": "~2.8|~3.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com",
"time": "2016-07-26 08:04:17"
},
{
"name": "symfony/console",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "f9e638e8149e9e41b570ff092f8007c477ef0ce5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/f9e638e8149e9e41b570ff092f8007c477ef0ce5",
"reference": "f9e638e8149e9e41b570ff092f8007c477ef0ce5",
"shasum": ""
},
"require": {
"php": ">=5.5.9",
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/event-dispatcher": "~2.8|~3.0",
"symfony/process": "~2.8|~3.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/process": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2016-07-26 08:04:17"
},
{
"name": "symfony/event-dispatcher",
"version": "v2.8.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "889983a79a043dfda68f38c38b6dba092dd49cd8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/889983a79a043dfda68f38c38b6dba092dd49cd8",
"reference": "889983a79a043dfda68f38c38b6dba092dd49cd8",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~2.0,>=2.0.5|~3.0.0",
"symfony/dependency-injection": "~2.6|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/stopwatch": "~2.3|~3.0.0"
},
"suggest": {
"symfony/dependency-injection": "",
"symfony/http-kernel": ""
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\EventDispatcher\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony EventDispatcher Component",
"homepage": "https://symfony.com",
"time": "2016-07-28 16:56:28"
},
{
"name": "symfony/filesystem",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "bb29adceb552d202b6416ede373529338136e84f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/bb29adceb552d202b6416ede373529338136e84f",
"reference": "bb29adceb552d202b6416ede373529338136e84f",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com",
"time": "2016-07-20 05:44:26"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "dff51f72b0706335131b00a7f49606168c582594"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
"reference": "dff51f72b0706335131b00a7f49606168c582594",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"time": "2016-05-18 14:26:46"
},
{
"name": "symfony/process",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/04c2dfaae4ec56a5c677b0c69fac34637d815758",
"reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-07-28 11:13:48"
},
{
"name": "symfony/stopwatch",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/stopwatch.git",
"reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/stopwatch/zipball/bb42806b12c5f89db4ebf64af6741afe6d8457e1",
"reference": "bb42806b12c5f89db4ebf64af6741afe6d8457e1",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Stopwatch\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Stopwatch Component",
"homepage": "https://symfony.com",
"time": "2016-06-29 05:41:56"
},
{
"name": "symfony/yaml",
"version": "v3.1.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "1819adf2066880c7967df7180f4f662b6f0567ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/1819adf2066880c7967df7180f4f662b6f0567ac",
"reference": "1819adf2066880c7967df7180f4f662b6f0567ac",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Yaml\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-07-17 14:02:08"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"codacy/coverage": 20,
"codeclimate/php-test-reporter": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^5.3 || ^7.0"
},
"platform-dev": []
}

View File

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

View File

@ -10,11 +10,12 @@
* @version 0.22 * @version 0.22
*/ */
namespace PrivateBin\model; namespace PrivateBin\Model;
use PrivateBin\Sjcl; use PrivateBin\Sjcl;
use PrivateBin\Persistence\TrafficLimiter; use PrivateBin\Persistence\TrafficLimiter;
use PrivateBin\Vizhash16x16; use PrivateBin\Vizhash16x16;
use Identicon\Identicon;
use Exception; use Exception;
/** /**
@ -192,17 +193,26 @@ class Comment extends AbstractModel
} }
$this->_data->meta->nickname = $nickname; $this->_data->meta->nickname = $nickname;
if ($this->_conf->getKey('vizhash')) { // If a nickname is provided, we generate an icon based on a SHA512 HMAC
// Generation of the anonymous avatar (Vizhash): // of the users IP. (We assume that if the user did not enter a nickname,
// If a nickname is provided, we generate a Vizhash. // the user wants to be anonymous and we will not generate an icon.)
// (We assume that if the user did not enter a nickname, he/she wants $icon = $this->_conf->getKey('icon');
// to be anonymous and we will not generate the vizhash.) if ($icon != 'none') {
$pngdata = '';
$hmac = TrafficLimiter::getHash();
if ($icon == 'identicon') {
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri($hmac, 16);
} elseif ($icon == 'vizhash') {
$vh = new Vizhash16x16(); $vh = new Vizhash16x16();
$pngdata = $vh->generate(TrafficLimiter::getIp()); $pngdata = 'data:image/png;base64,' . base64_encode(
$vh->generate($hmac)
);
}
if ($pngdata != '') { if ($pngdata != '') {
$this->_data->meta->vizhash = 'data:image/png;base64,' . base64_encode($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)); $randomSalt = bin2hex(mcrypt_create_iv(256, MCRYPT_DEV_URANDOM));
} else { } else {
// fallback to mt_rand() // fallback to mt_rand()
for ($i = 0; $i < 256; ++$i) { for ($i = 0; $i < 256; ++$i) {
$randomSalt .= base_convert(mt_rand(), 10, 16); $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 * @access public
* @static * @static
* @param string $algo
* @return string * @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; return true;
} }
$ip = hash_hmac('sha256', self::getIp(), ServerSalt::get());
$file = 'traffic_limiter.php'; $file = 'traffic_limiter.php';
if (!self::_exists($file)) { if (!self::_exists($file)) {
self::_store( self::_store(
@ -117,17 +116,19 @@ class TrafficLimiter extends AbstractPersistence
$now = time(); $now = time();
$tl = $GLOBALS['traffic_limiter']; $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) { foreach ($tl as $key => $time) {
if ($time + self::$_limit < $now) { if ($time + self::$_limit < $now) {
unset($tl[$key]); 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; $result = false;
} else { } else {
$tl[$ip] = time(); $tl[$hash] = time();
$result = true; $result = true;
} }
self::_store( self::_store(

View File

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

View File

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

View File

@ -5,7 +5,9 @@ use PrivateBin\Data\Database;
use PrivateBin\Model; use PrivateBin\Model;
use PrivateBin\Model\Paste; use PrivateBin\Model\Paste;
use PrivateBin\Persistence\ServerSalt; use PrivateBin\Persistence\ServerSalt;
use PrivateBin\Persistence\TrafficLimiter;
use PrivateBin\Vizhash16x16; use PrivateBin\Vizhash16x16;
use Identicon\Identicon;
class ModelTest extends PHPUnit_Framework_TestCase class ModelTest extends PHPUnit_Framework_TestCase
{ {
@ -167,13 +169,13 @@ class ModelTest extends PHPUnit_Framework_TestCase
$paste->setOpendiscussion(); $paste->setOpendiscussion();
$paste->store(); $paste->store();
$vz = new Vizhash16x16();
$pngdata = 'data:image/png;base64,' . base64_encode($vz->generate($_SERVER['REMOTE_ADDR']));
$comment = $paste->getComment(Helper::getPasteId()); $comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData['data']); $comment->setData($commentData['data']);
$comment->setNickname($commentData['meta']['nickname']); $comment->setNickname($commentData['meta']['nickname']);
$comment->store(); $comment->store();
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16);
$comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get(); $comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
$this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set'); $this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
} }
@ -260,9 +262,9 @@ class ModelTest extends PHPUnit_Framework_TestCase
public function testCommentWithDisabledVizhash() public function testCommentWithDisabledVizhash()
{ {
$options = parse_ini_file(CONF, true); $options = parse_ini_file(CONF, true);
$options['main']['vizhash'] = false; $options['main']['icon'] = 'none';
$options['model'] = array( $options['model'] = array(
'class' => 'privatebin_db', 'class' => 'Database',
); );
$options['model_options'] = array( $options['model_options'] = array(
'dsn' => 'sqlite::memory:', 'dsn' => 'sqlite::memory:',
@ -311,4 +313,80 @@ class ModelTest extends PHPUnit_Framework_TestCase
$this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname); $this->assertEquals($commentData['meta']['nickname'], $comment->meta->nickname);
$this->assertFalse(property_exists($comment->meta, 'vizhash'), 'vizhash was not generated'); $this->assertFalse(property_exists($comment->meta, 'vizhash'), 'vizhash was not generated');
} }
public function testCommentIdenticon()
{
$options = parse_ini_file(CONF, true);
$options['main']['icon'] = 'identicon';
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite::memory:',
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::confBackup();
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$pasteData = Helper::getPaste();
$commentData = Helper::getComment();
$model->getPaste(Helper::getPasteId())->delete();
$paste = $model->getPaste();
$paste->setData($pasteData['data']);
$paste->setOpendiscussion();
$paste->setFormatter($pasteData['meta']['formatter']);
$paste->store();
$comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData['data']);
$comment->setNickname($commentData['meta']['nickname']);
$comment->store();
$identicon = new Identicon();
$pngdata = $identicon->getImageDataUri(TrafficLimiter::getHash(), 16);
$comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
$this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
}
public function testCommentVizhash()
{
$options = parse_ini_file(CONF, true);
$options['main']['icon'] = 'vizhash';
$options['model'] = array(
'class' => 'Database',
);
$options['model_options'] = array(
'dsn' => 'sqlite::memory:',
'usr' => null,
'pwd' => null,
'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
);
Helper::confBackup();
Helper::createIniFile(CONF, $options);
$model = new Model(new Configuration);
$pasteData = Helper::getPaste();
$commentData = Helper::getComment();
$model->getPaste(Helper::getPasteId())->delete();
$paste = $model->getPaste();
$paste->setData($pasteData['data']);
$paste->setOpendiscussion();
$paste->setFormatter($pasteData['meta']['formatter']);
$paste->store();
$comment = $paste->getComment(Helper::getPasteId());
$comment->setData($commentData['data']);
$comment->setNickname($commentData['meta']['nickname']);
$comment->store();
$vz = new Vizhash16x16();
$pngdata = 'data:image/png;base64,' . base64_encode($vz->generate(TrafficLimiter::getHash()));
$comment = $paste->getComment(Helper::getPasteId(), Helper::getCommentId())->get();
$this->assertEquals($pngdata, $comment->meta->vizhash, 'nickname triggers vizhash to be set');
}
} }

View File

@ -30,11 +30,11 @@ class Vizhash16x16Test extends PHPUnit_Framework_TestCase
public function testVizhashGeneratesUniquePngsPerIp() public function testVizhashGeneratesUniquePngsPerIp()
{ {
$vz = new Vizhash16x16(); $vz = new Vizhash16x16();
$pngdata = $vz->generate('127.0.0.1'); $pngdata = $vz->generate(hash('sha512', '127.0.0.1'));
file_put_contents($this->_file, $pngdata); file_put_contents($this->_file, $pngdata);
$finfo = new finfo(FILEINFO_MIME_TYPE); $finfo = new finfo(FILEINFO_MIME_TYPE);
$this->assertEquals('image/png', $finfo->file($this->_file)); $this->assertEquals('image/png', $finfo->file($this->_file));
$this->assertNotEquals($pngdata, $vz->generate('2001:1620:2057:dead:beef::cafe:babe')); $this->assertNotEquals($pngdata, $vz->generate(hash('sha512', '2001:1620:2057:dead:beef::cafe:babe')));
$this->assertEquals($pngdata, $vz->generate('127.0.0.1')); $this->assertEquals($pngdata, $vz->generate(hash('sha512', '127.0.0.1')));
} }
} }

View File

@ -5,4 +5,29 @@
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array(); return array(
'Identicon\\Generator\\BaseGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
'Identicon\\Generator\\GdGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
'Identicon\\Generator\\GeneratorInterface' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
'Identicon\\Generator\\ImageMagickGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
'Identicon\\Identicon' => $vendorDir . '/yzalis/identicon/src/Identicon/Identicon.php',
'PrivateBin\\Configuration' => $baseDir . '/lib/Configuration.php',
'PrivateBin\\Data\\AbstractData' => $baseDir . '/lib/Data/AbstractData.php',
'PrivateBin\\Data\\Database' => $baseDir . '/lib/Data/Database.php',
'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
'PrivateBin\\I18n' => $baseDir . '/lib/I18n.php',
'PrivateBin\\Model' => $baseDir . '/lib/Model.php',
'PrivateBin\\Model\\AbstractModel' => $baseDir . '/lib/Model/AbstractModel.php',
'PrivateBin\\Model\\Comment' => $baseDir . '/lib/Model/Comment.php',
'PrivateBin\\Model\\Paste' => $baseDir . '/lib/Model/Paste.php',
'PrivateBin\\Persistence\\AbstractPersistence' => $baseDir . '/lib/Persistence/AbstractPersistence.php',
'PrivateBin\\Persistence\\PurgeLimiter' => $baseDir . '/lib/Persistence/PurgeLimiter.php',
'PrivateBin\\Persistence\\ServerSalt' => $baseDir . '/lib/Persistence/ServerSalt.php',
'PrivateBin\\Persistence\\TrafficLimiter' => $baseDir . '/lib/Persistence/TrafficLimiter.php',
'PrivateBin\\PrivateBin' => $baseDir . '/lib/PrivateBin.php',
'PrivateBin\\Request' => $baseDir . '/lib/Request.php',
'PrivateBin\\Sjcl' => $baseDir . '/lib/Sjcl.php',
'PrivateBin\\View' => $baseDir . '/lib/View.php',
'PrivateBin\\Vizhash16x16' => $baseDir . '/lib/Vizhash16x16.php',
);

View File

@ -1,8 +0,0 @@
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array();

View File

@ -6,10 +6,5 @@ $vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(
'Psr\\Log\\' => array($vendorDir . '/psr/log'), 'Identicon' => array($vendorDir . '/yzalis/identicon/src'),
'Prophecy\\' => array($vendorDir . '/phpspec/prophecy/src'),
'Guzzle\\Tests' => array($vendorDir . '/guzzle/guzzle/tests'),
'Guzzle' => array($vendorDir . '/guzzle/guzzle/src'),
'CodeClimate\\Component' => array($vendorDir . '/codeclimate/php-test-reporter/src'),
'CodeClimate\\Bundle' => array($vendorDir . '/codeclimate/php-test-reporter/src'),
); );

View File

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

View File

@ -6,8 +6,6 @@ namespace Composer\Autoload;
class ComposerStaticInitDontChange class ComposerStaticInitDontChange
{ {
public static $files = array ();
public static $prefixLengthsPsr4 = array ( public static $prefixLengthsPsr4 = array (
'P' => 'P' =>
array ( array (
@ -22,9 +20,42 @@ class ComposerStaticInitDontChange
), ),
); );
public static $prefixesPsr0 = array (); public static $prefixesPsr0 = array (
'I' =>
array (
'Identicon' =>
array (
0 => __DIR__ . '/..' . '/yzalis/identicon/src',
),
),
);
public static $classMap = array (); public static $classMap = array (
'Identicon\\Generator\\BaseGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',
'Identicon\\Generator\\GdGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GdGenerator.php',
'Identicon\\Generator\\GeneratorInterface' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/GeneratorInterface.php',
'Identicon\\Generator\\ImageMagickGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/ImageMagickGenerator.php',
'Identicon\\Identicon' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Identicon.php',
'PrivateBin\\Configuration' => __DIR__ . '/../..' . '/lib/Configuration.php',
'PrivateBin\\Data\\AbstractData' => __DIR__ . '/../..' . '/lib/Data/AbstractData.php',
'PrivateBin\\Data\\Database' => __DIR__ . '/../..' . '/lib/Data/Database.php',
'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
'PrivateBin\\I18n' => __DIR__ . '/../..' . '/lib/I18n.php',
'PrivateBin\\Model' => __DIR__ . '/../..' . '/lib/Model.php',
'PrivateBin\\Model\\AbstractModel' => __DIR__ . '/../..' . '/lib/Model/AbstractModel.php',
'PrivateBin\\Model\\Comment' => __DIR__ . '/../..' . '/lib/Model/Comment.php',
'PrivateBin\\Model\\Paste' => __DIR__ . '/../..' . '/lib/Model/Paste.php',
'PrivateBin\\Persistence\\AbstractPersistence' => __DIR__ . '/../..' . '/lib/Persistence/AbstractPersistence.php',
'PrivateBin\\Persistence\\PurgeLimiter' => __DIR__ . '/../..' . '/lib/Persistence/PurgeLimiter.php',
'PrivateBin\\Persistence\\ServerSalt' => __DIR__ . '/../..' . '/lib/Persistence/ServerSalt.php',
'PrivateBin\\Persistence\\TrafficLimiter' => __DIR__ . '/../..' . '/lib/Persistence/TrafficLimiter.php',
'PrivateBin\\PrivateBin' => __DIR__ . '/../..' . '/lib/PrivateBin.php',
'PrivateBin\\Request' => __DIR__ . '/../..' . '/lib/Request.php',
'PrivateBin\\Sjcl' => __DIR__ . '/../..' . '/lib/Sjcl.php',
'PrivateBin\\View' => __DIR__ . '/../..' . '/lib/View.php',
'PrivateBin\\Vizhash16x16' => __DIR__ . '/../..' . '/lib/Vizhash16x16.php',
);
public static function getInitializer(ClassLoader $loader) public static function getInitializer(ClassLoader $loader)
{ {

View File

@ -1 +1,54 @@
[] [
{
"name": "yzalis/identicon",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/yzalis/Identicon.git",
"reference": "a99fc2a3d018512f7914bc6f972952536c0f309b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/yzalis/Identicon/zipball/a99fc2a3d018512f7914bc6f972952536c0f309b",
"reference": "a99fc2a3d018512f7914bc6f972952536c0f309b",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"fzaninotto/faker": "1.2.*@dev"
},
"time": "2014-07-13 09:19:12",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Identicon": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Benjamin Laugueux",
"email": "benjamin@yzalis.com"
}
],
"description": "Create awesome unique avatar.",
"homepage": "http://identicon-php.org",
"keywords": [
"avatar",
"identicon",
"image"
]
}
]

View File

@ -0,0 +1,241 @@
<?php
namespace Identicon\Generator;
use Identicon\Generator\GeneratorInterface;
/**
* @author Benjamin Laugueux <benjamin@yzalis.com>
*/
class BaseGenerator
{
/**
* @var mixed
*/
protected $generatedImage;
/**
* @var integer
*/
protected $color;
/**
* @var integer
*/
protected $backgroundColor;
/**
* @var integer
*/
protected $size;
/**
* @var integer
*/
protected $pixelRatio;
/**
* @var string
*/
private $hash;
/**
* @var array
*/
private $arrayOfSquare = array();
/**
* Set the image color
*
* @param string|array $color The color in hexa (6 chars) or rgb array
*
* @return this
*/
public function setColor($color)
{
if (null === $color) {
return $this;
}
$this->color = $this->convertColor($color);
return $this;
}
/**
* Set the image background color
*
* @param string|array $backgroundColor The color in hexa (6 chars) or rgb array
*
* @return this
*/
public function setBackgroundColor($backgroundColor)
{
if (null === $backgroundColor) {
return $this;
}
$this->backgroundColor = $this->convertColor($backgroundColor);
return $this;
}
private function convertColor($color)
{
$convertedColor = array();
if (is_array($color)) {
$convertedColor[0] = $color[0];
$convertedColor[1] = $color[1];
$convertedColor[2] = $color[2];
} else {
if (false !== strpos($color, '#')) {
$color = substr($color, 1);
}
$convertedColor[0] = hexdec(substr($color, 0, 2));
$convertedColor[1] = hexdec(substr($color, 2, 2));
$convertedColor[2] = hexdec(substr($color, 4, 2));
}
return $convertedColor;
}
/**
* Get the color
*
* @return array
*/
public function getColor()
{
return $this->color;
}
/**
* Get the background color
*
* @return array
*/
public function getBackgroundColor()
{
return $this->backgroundColor;
}
/**
* Convert the hash into an multidimensionnal array of boolean
*
* @return this
*/
private function convertHashToArrayOfBoolean()
{
preg_match_all('/(\w)(\w)/', $this->hash, $chars);
foreach ($chars[1] as $i => $char) {
if ($i % 3 == 0) {
$this->arrayOfSquare[$i/3][0] = $this->convertHexaToBoolean($char);
$this->arrayOfSquare[$i/3][4] = $this->convertHexaToBoolean($char);
} elseif ($i % 3 == 1) {
$this->arrayOfSquare[$i/3][1] = $this->convertHexaToBoolean($char);
$this->arrayOfSquare[$i/3][3] = $this->convertHexaToBoolean($char);
} else {
$this->arrayOfSquare[$i/3][2] = $this->convertHexaToBoolean($char);
}
ksort($this->arrayOfSquare[$i/3]);
}
$this->color[0] = hexdec(array_pop($chars[1]))*16;
$this->color[1] = hexdec(array_pop($chars[1]))*16;
$this->color[2] = hexdec(array_pop($chars[1]))*16;
return $this;
}
/**
* Convert an heaxecimal number into a boolean
*
* @param string $hexa
*
* @return boolean
*/
private function convertHexaToBoolean($hexa)
{
return (bool) intval(round(hexdec($hexa)/10));
}
/**
*
*
* @return array
*/
public function getArrayOfSquare()
{
return $this->arrayOfSquare;
}
/**
* Get the identicon string hash
*
* @return string
*/
public function getHash()
{
return $this->hash;
}
/**
* Generate a hash fron the original string
*
* @param string $string
*
* @return this
*/
public function setString($string)
{
if (null === $string) {
throw new \Exception('The string cannot be null.');
}
$this->hash = md5($string);
$this->convertHashToArrayOfBoolean();
return $this;
}
/**
* Set the image size
*
* @param integer $size
*
* @return this
*/
public function setSize($size)
{
if (null === $size) {
return $this;
}
$this->size = $size;
$this->pixelRatio = round($size / 5);
return $this;
}
/**
* Get the image size
*
* @return integer
*/
public function getSize()
{
return $this->size;
}
/**
* Get the pixel ratio
*
* @return array
*/
public function getPixelRatio()
{
return $this->pixelRatio;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Identicon\Generator;
use Identicon\Generator\GeneratorInterface;
/**
* @author Benjamin Laugueux <benjamin@yzalis.com>
*/
class GdGenerator extends BaseGenerator implements GeneratorInterface
{
public function __construct()
{
if (!extension_loaded('gd')) {
throw new \Exception('GD does not appear to be avaliable in your PHP installation. Please try another generator');
}
}
private function generateImage()
{
// prepare image
$this->generatedImage = imagecreatetruecolor($this->getPixelRatio() * 5, $this->getPixelRatio() * 5);
$rgbBackgroundColor = $this->getBackgroundColor();
if (null === $rgbBackgroundColor) {
$background = imagecolorallocate($this->generatedImage, 0, 0, 0);
imagecolortransparent($this->generatedImage, $background);
} else {
$background = imagecolorallocate($this->generatedImage, $rgbBackgroundColor[0], $rgbBackgroundColor[1], $rgbBackgroundColor[2]);
imagefill($this->generatedImage, 0, 0, $background);
}
// prepage color
$rgbColor = $this->getColor();
$gdColor = imagecolorallocate($this->generatedImage, $rgbColor[0], $rgbColor[1], $rgbColor[2]);
// draw content
foreach ($this->getArrayOfSquare() as $lineKey => $lineValue) {
foreach ($lineValue as $colKey => $colValue) {
if (true === $colValue) {
imagefilledrectangle($this->generatedImage, $colKey * $this->getPixelRatio(), $lineKey * $this->getPixelRatio(), ($colKey + 1) * $this->getPixelRatio(), ($lineKey + 1) * $this->getPixelRatio(), $gdColor);
}
}
}
return $this;
}
/**
* {@inheritDoc}
*/
public function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null)
{
ob_start();
imagepng($this->getImageResource($string, $size, $color, $backgroundColor));
$imageData = ob_get_contents();
ob_end_clean();
return $imageData;
}
/**
* {@inheritDoc}
*/
public function getImageResource($string, $size = null, $color = null, $backgroundColor = null)
{
$this
->setString($string)
->setSize($size)
->setColor($color)
->setBackgroundColor($backgroundColor)
->generateImage();
return $this->generatedImage;
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace Identicon\Generator;
/**
* @author Benjamin Laugueux <benjamin@yzalis.com>
*/
interface GeneratorInterface
{
/**
*
*
* @param string $string
* @param integer $size
* @param array|string $color
* @param array|string $backgroundColor
*
* @return mixed
*/
function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null);
/**
*
*
* @param string $string
* @param integer $size
* @param array|string $color
* @param array|string $backgroundColor
*
* @return string
*/
function getImageResource($string, $size = null, $color = null, $backgroundColor = null);
}

View File

@ -0,0 +1,80 @@
<?php
namespace Identicon\Generator;
use Identicon\Generator\GeneratorInterface;
/**
* @author Francis Chuang <francis.chuang@gmail.com>
*/
class ImageMagickGenerator extends BaseGenerator implements GeneratorInterface
{
public function __construct()
{
if (!extension_loaded('imagick')) {
throw new \Exception('ImageMagick does not appear to be avaliable in your PHP installation. Please try another generator');
}
}
private function generateImage()
{
$this->generatedImage = new \Imagick();
$rgbBackgroundColor = $this->getBackgroundColor();
if (null === $rgbBackgroundColor) {
$background = 'none';
} else {
$background = new \ImagickPixel("rgb($rgbBackgroundColor[0],$rgbBackgroundColor[1],$rgbBackgroundColor[2])");
}
$this->generatedImage->newImage($this->pixelRatio * 5, $this->pixelRatio * 5, $background, 'png');
// prepare color
$rgbColor = $this->getColor();
$color = new \ImagickPixel("rgb($rgbColor[0],$rgbColor[1],$rgbColor[2])");
$draw = new \ImagickDraw();
$draw->setFillColor($color);
// draw the content
foreach ($this->getArrayOfSquare() as $lineKey => $lineValue) {
foreach ($lineValue as $colKey => $colValue) {
if (true === $colValue) {
$draw->rectangle( $colKey * $this->pixelRatio, $lineKey * $this->pixelRatio, ($colKey + 1) * $this->pixelRatio, ($lineKey + 1) * $this->pixelRatio);
}
}
}
$this->generatedImage->drawImage($draw);
return $this;
}
/**
* {@inheritDoc}
*/
public function getImageBinaryData($string, $size = null, $color = null, $backgroundColor = null)
{
ob_start();
echo $this->getImageResource($string, $size, $color, $backgroundColor);
$imageData = ob_get_contents();
ob_end_clean();
return $imageData;
}
/**
* {@inheritDoc}
*/
public function getImageResource($string, $size = null, $color = null, $backgroundColor = null)
{
$this
->setString($string)
->setSize($size)
->setColor($color)
->setBackgroundColor($backgroundColor)
->generateImage();
return $this->generatedImage;
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace Identicon;
use Identicon\Generator\GdGenerator;
use Identicon\Generator\GeneratorInterface;
/**
* @author Benjamin Laugueux <benjamin@yzalis.com>
*/
class Identicon
{
/**
* @var GeneratorInterface
*/
private $generator;
public function __construct($generator = null)
{
if (null === $generator) {
$this->generator = new GdGenerator();
} else {
$this->generator = $generator;
}
}
/**
* Set the image generetor
*
* @param GeneratorInterface $generator
*
* @throws \Exception
*/
public function setGenerator(GeneratorInterface $generator)
{
$this->generator = $generator;
return $this;
}
/**
* Display an Identicon image
*
* @param string $string
* @param integer $size
* @param string $color
* @param string $backgroundColor
*/
public function displayImage($string, $size = 64, $color = null, $backgroundColor = null)
{
header("Content-Type: image/png");
echo $this->getImageData($string, $size, $color, $backgroundColor);
}
/**
* Get an Identicon PNG image data
*
* @param string $string
* @param integer $size
* @param string $color
* @param string $backgroundColor
*
* @return string
*/
public function getImageData($string, $size = 64, $color = null, $backgroundColor = null)
{
return $this->generator->getImageBinaryData($string, $size, $color, $backgroundColor);
}
/**
* Get an Identicon PNG image resource
*
* @param string $string
* @param integer $size
* @param string $color
* @param string $backgroundColor
*
* @return string
*/
public function getImageResource($string, $size = 64, $color = null, $backgroundColor = null)
{
return $this->generator->getImageResource($string, $size, $color, $backgroundColor);
}
/**
* Get an Identicon PNG image data as base 64 encoded
*
* @param string $string
* @param integer $size
* @param string $color
* @param string $backgroundColor
*
* @return string
*/
public function getImageDataUri($string, $size = 64, $color = null, $backgroundColor = null)
{
return sprintf('data:image/png;base64,%s', base64_encode($this->getImageData($string, $size, $color, $backgroundColor)));
}
}