Merge pull request #1672 from PrivateBin/purify-3.2.7

Upgrading libraries to: bootstrap 5.3.8, DOMpurify 3.2.7 & ip-lib 1.21.0
This commit is contained in:
El RIDO 2025-10-10 07:14:18 +02:00 committed by GitHub
commit 7779f1ac65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 624 additions and 151 deletions

View file

@ -5,6 +5,7 @@
* ADDED: Added `shortenviashlink` endpoint with an `shlink` configuration section
* ADDED: Password peek (#1254)
* CHANGED: CSP recommendation around bootstrap5 template resolved in Firefox 131 (#1613)
* CHANGED: Upgrading libraries to: bootstrap 5.3.8, DOMpurify 3.2.7 & ip-lib 1.21.0
* FIXED: Allow pasting a password for decrypting a paste (#1620)
* FIXED: Allow copying the shortened link after using a URL shortener (#1624)
* FIXED: URL extraction fails when frame-ancestors is set in CSP (#1644)

View file

@ -26,7 +26,7 @@
"require" : {
"php": "^7.4 || ^8.0",
"jdenticon/jdenticon": "2.0.0",
"mlocati/ip-lib": "1.20.0",
"mlocati/ip-lib": "1.21.0",
"symfony/polyfill-php80": "1.31.0",
"yzalis/identicon": "2.0.0"
},

156
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "cc778a671eac2ba1ec70bf9398b2e1bf",
"content-hash": "f008f704483472b237031d4fa389cb70",
"packages": [
{
"name": "jdenticon/jdenticon",
@ -57,16 +57,16 @@
},
{
"name": "mlocati/ip-lib",
"version": "1.20.0",
"version": "1.21.0",
"source": {
"type": "git",
"url": "https://github.com/mlocati/ip-lib.git",
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4"
"reference": "b5d38cdcbfc1516604d821a1f3f4a1638f327267"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/fd45fc3bf08ed6c7e665e2e70562082ac954afd4",
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/b5d38cdcbfc1516604d821a1f3f4a1638f327267",
"reference": "b5d38cdcbfc1516604d821a1f3f4a1638f327267",
"shasum": ""
},
"require": {
@ -112,7 +112,7 @@
],
"support": {
"issues": "https://github.com/mlocati/ip-lib/issues",
"source": "https://github.com/mlocati/ip-lib/tree/1.20.0"
"source": "https://github.com/mlocati/ip-lib/tree/1.21.0"
},
"funding": [
{
@ -124,7 +124,7 @@
"type": "other"
}
],
"time": "2025-02-04T17:30:58+00:00"
"time": "2025-09-24T13:58:50+00:00"
},
{
"name": "symfony/polyfill-php80",
@ -337,16 +337,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.13.3",
"version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
@ -385,7 +385,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
},
"funding": [
{
@ -393,20 +393,20 @@
"type": "tidelift"
}
],
"time": "2025-07-05T12:25:42+00:00"
"time": "2025-08-01T08:46:24+00:00"
},
{
"name": "nikic/php-parser",
"version": "v5.5.0",
"version": "v5.6.1",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
"shasum": ""
},
"require": {
@ -425,7 +425,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.0-dev"
"dev-master": "5.x-dev"
}
},
"autoload": {
@ -449,9 +449,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
},
"time": "2025-05-31T08:24:38+00:00"
"time": "2025-08-13T20:13:15+00:00"
},
{
"name": "phar-io/manifest",
@ -892,16 +892,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.23",
"version": "9.6.29",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95"
"reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
"reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
"shasum": ""
},
"require": {
@ -912,7 +912,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.13.1",
"myclabs/deep-copy": "^1.13.4",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=7.3",
@ -923,11 +923,11 @@
"phpunit/php-timer": "^5.0.3",
"sebastian/cli-parser": "^1.0.2",
"sebastian/code-unit": "^1.0.8",
"sebastian/comparator": "^4.0.8",
"sebastian/comparator": "^4.0.9",
"sebastian/diff": "^4.0.6",
"sebastian/environment": "^5.1.5",
"sebastian/exporter": "^4.0.6",
"sebastian/global-state": "^5.0.7",
"sebastian/exporter": "^4.0.8",
"sebastian/global-state": "^5.0.8",
"sebastian/object-enumerator": "^4.0.4",
"sebastian/resource-operations": "^3.0.4",
"sebastian/type": "^3.2.1",
@ -975,7 +975,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29"
},
"funding": [
{
@ -999,7 +999,7 @@
"type": "tidelift"
}
],
"time": "2025-05-02T06:40:34+00:00"
"time": "2025-09-24T06:29:11+00:00"
},
{
"name": "sebastian/cli-parser",
@ -1170,16 +1170,16 @@
},
{
"name": "sebastian/comparator",
"version": "4.0.8",
"version": "4.0.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "fa0f136dd2334583309d32b62544682ee972b51a"
"reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
"reference": "fa0f136dd2334583309d32b62544682ee972b51a",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
"reference": "67a2df3a62639eab2cc5906065e9805d4fd5dfc5",
"shasum": ""
},
"require": {
@ -1232,15 +1232,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
"source": "https://github.com/sebastianbergmann/comparator/tree/4.0.9"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/comparator",
"type": "tidelift"
}
],
"time": "2022-09-14T12:41:17+00:00"
"time": "2025-08-10T06:51:50+00:00"
},
{
"name": "sebastian/complexity",
@ -1430,16 +1442,16 @@
},
{
"name": "sebastian/exporter",
"version": "4.0.6",
"version": "4.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
"reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
"reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/14c6ba52f95a36c3d27c835d65efc7123c446e8c",
"reference": "14c6ba52f95a36c3d27c835d65efc7123c446e8c",
"shasum": ""
},
"require": {
@ -1495,28 +1507,40 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
"source": "https://github.com/sebastianbergmann/exporter/tree/4.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/exporter",
"type": "tidelift"
}
],
"time": "2024-03-02T06:33:00+00:00"
"time": "2025-09-24T06:03:27+00:00"
},
{
"name": "sebastian/global-state",
"version": "5.0.7",
"version": "5.0.8",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
"reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
"reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
"url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
"reference": "b6781316bdcd28260904e7cc18ec983d0d2ef4f6",
"shasum": ""
},
"require": {
@ -1559,15 +1583,27 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
"source": "https://github.com/sebastianbergmann/global-state/tree/5.0.8"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/global-state",
"type": "tidelift"
}
],
"time": "2024-03-02T06:35:11+00:00"
"time": "2025-08-10T07:10:35+00:00"
},
{
"name": "sebastian/lines-of-code",
@ -1740,16 +1776,16 @@
},
{
"name": "sebastian/recursion-context",
"version": "4.0.5",
"version": "4.0.6",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
"reference": "539c6691e0623af6dc6f9c20384c120f963465a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
"reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/539c6691e0623af6dc6f9c20384c120f963465a0",
"reference": "539c6691e0623af6dc6f9c20384c120f963465a0",
"shasum": ""
},
"require": {
@ -1791,15 +1827,27 @@
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
"source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.6"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
"type": "tidelift"
}
],
"time": "2023-02-03T06:07:39+00:00"
"time": "2025-08-10T06:57:39+00:00"
},
{
"name": "sebastian/resource-operations",

File diff suppressed because one or more lines are too long

5
css/bootstrap5/bootstrap-5.3.8.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
js/bootstrap-5.3.8.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -15,7 +15,7 @@ require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.2.6');
global.DOMPurify = require('./purify-3.2.7');
global.baseX = require('./base-x-5.0.1').baseX;
global.Legacy = require('./legacy').Legacy;
require('./privatebin');

File diff suppressed because one or more lines are too long

2
js/purify-3.2.7.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -23,7 +23,7 @@ describe('Prompt', function () {
$.PrivateBin.Model.reset();
$.PrivateBin.Model.init();
// eslint-disable-next-line global-require
global.bootstrap = require('../bootstrap-5.3.7');
global.bootstrap = require('../bootstrap-5.3.8');
$.PrivateBin.Prompt.init();
$.PrivateBin.Prompt.requestPassword();
$('#passworddecrypt').val(password);

View file

@ -115,14 +115,14 @@ class Configuration
'sri' => array(
'js/base-x-5.0.1.js' => 'sha512-FmhlnjIxQyxkkxQmzf0l6IRGsGbgyCdgqPxypFsEtHMF1naRqaLLo6mcyN5rEaT16nKx1PeJ4g7+07D6gnk/Tg==',
'js/bootstrap-3.4.1.js' => 'sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==',
'js/bootstrap-5.3.7.js' => 'sha512-UqmrCkPcp6WOB9cC/NB5GB7vQd2/sB70bLpFk0bqHz/WQIFucjAM0vFNI4xp8B7jJ8KIUWPblNAS/M30AHKSzA==',
'js/bootstrap-5.3.8.js' => 'sha512-BkZvJ5rZ3zbDCod5seWHpRGg+PRd6ZgE8Nua/OMtcxqm8Wtg0PqwhUUXK5bqvl3oclMt5O+3zjRVX0L+L2j7fA==',
'js/dark-mode-switch.js' => 'sha512-BhY7dNU14aDN5L+muoUmA66x0CkYUWkQT0nxhKBLP/o2d7jE025+dvWJa4OiYffBGEFgmhrD/Sp+QMkxGMTz2g==',
'js/jquery-3.7.1.js' => 'sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==',
'js/kjua-0.10.0.js' => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==',
'js/legacy.js' => 'sha512-rGXYUpIqbFoHAgBXZ0UlJBdNAIMOC9EQ67MG0X46D5uRB8LvwzgKirbSQRGdYfk8I2jsUcm+tvHXYboUnC6DUg==',
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
'js/privatebin.js' => 'sha512-28TbF+KEbUv22X+tVm5a0ik1qQGtjqcKoSuXA+jFZqC9zyFF8Km+V2rSDqwgF0hf38WMVp5F2k0T6u/bKJLpSQ==',
'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==',
'js/privatebin.js' => 'sha512-2F02E/UQoQyCNk0FvwaOLD9MvDhtuYqTtGKdqwsbDjY4O0jMZjn/EtiP2wvS0uxYojkxeUitF0HWb+RDFUwQXg==',
'js/purify-3.2.7.js' => 'sha512-2H9wzIiPQCOsh7T3hK/WuqWIwSQ2oYq91doyrp1LcnXuPyxzehopypz16wiWqxmMjx2cVIqAWCoRp1gNZAsFEQ==',
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',
),

View file

@ -65,7 +65,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.2.6.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.2.7.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->

View file

@ -10,7 +10,7 @@ use PrivateBin\I18n;
<meta name="robots" content="noindex" />
<meta name="google" content="notranslate">
<title><?php echo I18n::_($NAME); ?></title>
<link type="text/css" rel="stylesheet" href="css/bootstrap5/bootstrap<?php echo I18n::isRtl() ? '.rtl' : ''; ?>-5.3.7.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap5/bootstrap<?php echo I18n::isRtl() ? '.rtl' : ''; ?>-5.3.8.css" />
<link type="text/css" rel="stylesheet" href="css/bootstrap5/privatebin.css?<?php echo rawurlencode($VERSION); ?>" />
<?php
if ($SYNTAXHIGHLIGHTING) :
@ -35,7 +35,7 @@ endif;
?>
<?php $this->_scriptTag('js/zlib-1.3.1-1.js', 'defer'); ?>
<?php $this->_scriptTag('js/base-x-5.0.1.js', 'defer'); ?>
<?php $this->_scriptTag('js/bootstrap-5.3.7.js', 'defer'); ?>
<?php $this->_scriptTag('js/bootstrap-5.3.8.js', 'defer'); ?>
<?php $this->_scriptTag('js/dark-mode-switch.js', 'defer'); ?>
<?php
if ($SYNTAXHIGHLIGHTING) :
@ -49,7 +49,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.2.6.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.2.7.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->

View file

@ -22,6 +22,7 @@ return array(
'IPLib\\Range\\Subnet' => $vendorDir . '/mlocati/ip-lib/src/Range/Subnet.php',
'IPLib\\Range\\Type' => $vendorDir . '/mlocati/ip-lib/src/Range/Type.php',
'IPLib\\Service\\BinaryMath' => $vendorDir . '/mlocati/ip-lib/src/Service/BinaryMath.php',
'IPLib\\Service\\NumberInChunks' => $vendorDir . '/mlocati/ip-lib/src/Service/NumberInChunks.php',
'IPLib\\Service\\RangesFromBoundaryCalculator' => $vendorDir . '/mlocati/ip-lib/src/Service/RangesFromBoundaryCalculator.php',
'IPLib\\Service\\UnsignedIntegerMath' => $vendorDir . '/mlocati/ip-lib/src/Service/UnsignedIntegerMath.php',
'Identicon\\Generator\\BaseGenerator' => $vendorDir . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',

View file

@ -70,6 +70,7 @@ class ComposerStaticInitDontChange
'IPLib\\Range\\Subnet' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Subnet.php',
'IPLib\\Range\\Type' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Range/Type.php',
'IPLib\\Service\\BinaryMath' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/BinaryMath.php',
'IPLib\\Service\\NumberInChunks' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/NumberInChunks.php',
'IPLib\\Service\\RangesFromBoundaryCalculator' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/RangesFromBoundaryCalculator.php',
'IPLib\\Service\\UnsignedIntegerMath' => __DIR__ . '/..' . '/mlocati/ip-lib/src/Service/UnsignedIntegerMath.php',
'Identicon\\Generator\\BaseGenerator' => __DIR__ . '/..' . '/yzalis/identicon/src/Identicon/Generator/BaseGenerator.php',

View file

@ -3,7 +3,7 @@
'name' => 'privatebin/privatebin',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '3ba29ea29e04d8a16d64e0f49994ba416c1b008f',
'reference' => '06496a1b0e975b79c5a7abc0bd54b492ca264640',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@ -20,9 +20,9 @@
'dev_requirement' => false,
),
'mlocati/ip-lib' => array(
'pretty_version' => '1.20.0',
'version' => '1.20.0.0',
'reference' => 'fd45fc3bf08ed6c7e665e2e70562082ac954afd4',
'pretty_version' => '1.21.0',
'version' => '1.21.0.0',
'reference' => 'b5d38cdcbfc1516604d821a1f3f4a1638f327267',
'type' => 'library',
'install_path' => __DIR__ . '/../mlocati/ip-lib',
'aliases' => array(),
@ -31,7 +31,7 @@
'privatebin/privatebin' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
'reference' => '3ba29ea29e04d8a16d64e0f49994ba416c1b008f',
'reference' => '06496a1b0e975b79c5a7abc0bd54b492ca264640',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),

View file

@ -110,11 +110,12 @@ interface AddressInterface
/**
* Get the address at a certain distance from this address.
*
* @param int $n the distance of the address (can be negative)
* @param int|numeric-string $n the distance of the address (can be negative)
*
* @return \IPLib\Address\AddressInterface|null return NULL if $n is not an integer or if the final address would be invalid
* @return \IPLib\Address\AddressInterface|null return NULL if $n is not an integer or NULL if $n is neither an integer nor a string containing a valid integer, or if the final address would be invalid
*
* @since 1.15.0
* @since 1.21.0 $n can also be a numeric string
*
* @example passing 1 to the address 127.0.0.1 will result in 127.0.0.2
* @example passing -1 to the address 127.0.0.1 will result in 127.0.0.0

View file

@ -6,6 +6,8 @@ use IPLib\ParseStringFlag;
use IPLib\Range\RangeInterface;
use IPLib\Range\Subnet;
use IPLib\Range\Type as RangeType;
use IPLib\Service\BinaryMath;
use IPLib\Service\NumberInChunks;
/**
* An IPv4 address.
@ -456,28 +458,24 @@ class IPv4 implements AddressInterface
*/
public function getAddressAtOffset($n)
{
if (!is_int($n)) {
if (is_int($n)) {
$thatChunks = NumberInChunks::fromInteger($n, NumberInChunks::CHUNKSIZE_BYTES);
} elseif (($s = BinaryMath::getInstance()->normalizeIntegerString($n)) !== '') {
$thatChunks = NumberInChunks::fromNumericString($s, NumberInChunks::CHUNKSIZE_BYTES);
} else {
return null;
}
$myBytes = $this->getBytes();
while (isset($myBytes[1]) && $myBytes[0] === 0) {
array_shift($myBytes);
}
$myChunks = new NumberInChunks(false, $myBytes, NumberInChunks::CHUNKSIZE_BYTES);
$result = $myChunks->add($thatChunks);
if ($result->negative || count($result->chunks) > 4) {
return null;
}
$boundary = 256;
$mod = $n;
$bytes = $this->getBytes();
for ($i = count($bytes) - 1; $i >= 0; $i--) {
$tmp = ($bytes[$i] + $mod) % $boundary;
$mod = (int) floor(($bytes[$i] + $mod) / $boundary);
if ($tmp < 0) {
$tmp += $boundary;
}
$bytes[$i] = $tmp;
}
if ($mod !== 0) {
return null;
}
return static::fromBytes($bytes);
return static::fromBytes(array_pad($result->chunks, -4, 0));
}
/**

View file

@ -6,6 +6,8 @@ use IPLib\ParseStringFlag;
use IPLib\Range\RangeInterface;
use IPLib\Range\Subnet;
use IPLib\Range\Type as RangeType;
use IPLib\Service\BinaryMath;
use IPLib\Service\NumberInChunks;
/**
* An IPv6 address.
@ -549,28 +551,24 @@ class IPv6 implements AddressInterface
*/
public function getAddressAtOffset($n)
{
if (!is_int($n)) {
if (is_int($n)) {
$thatChunks = NumberInChunks::fromInteger($n, NumberInChunks::CHUNKSIZE_WORDS);
} elseif (($s = BinaryMath::getInstance()->normalizeIntegerString($n)) !== '') {
$thatChunks = NumberInChunks::fromNumericString($s, NumberInChunks::CHUNKSIZE_WORDS);
} else {
return null;
}
$myWords = $this->getWords();
while (isset($myWords[1]) && $myWords[0] === 0) {
array_shift($myWords);
}
$myChunks = new NumberInChunks(false, $myWords, NumberInChunks::CHUNKSIZE_WORDS);
$result = $myChunks->add($thatChunks);
if ($result->negative || count($result->chunks) > 8) {
return null;
}
$boundary = 0x10000;
$mod = $n;
$words = $this->getWords();
for ($i = count($words) - 1; $i >= 0; $i--) {
$tmp = ($words[$i] + $mod) % $boundary;
$mod = (int) floor(($words[$i] + $mod) / $boundary);
if ($tmp < 0) {
$tmp += $boundary;
}
$words[$i] = $tmp;
}
if ($mod !== 0) {
return null;
}
return static::fromWords($words);
return static::fromWords(array_pad($result->chunks, -8, 0));
}
/**
@ -645,7 +643,7 @@ class IPv6 implements AddressInterface
}
$myWords = $this->getWords();
$otherWords = $other->getWords();
$sum = array_fill(0, 7, 0);
$sum = array_fill(0, 8, 0);
$carry = 0;
for ($index = 7; $index >= 0; $index--) {
$word = $myWords[$index] + $otherWords[$index] + $carry;

View file

@ -7,6 +7,7 @@ use IPLib\Address\IPv4;
use IPLib\Address\IPv6;
use IPLib\Address\Type as AddressType;
use IPLib\Factory;
use IPLib\Service\BinaryMath;
use OutOfBoundsException;
/**
@ -59,17 +60,26 @@ abstract class AbstractRange implements RangeInterface
*/
public function getAddressAtOffset($n)
{
if (!is_int($n)) {
if (is_int($n)) {
$positive = $n >= 0;
if ($positive === false) {
$nPlus1 = $n + 1;
}
} elseif (($s = BinaryMath::getInstance()->normalizeIntegerString($n)) !== '') {
$n = $s;
$positive = $n[0] !== '-';
if ($positive === false) {
$nPlus1 = BinaryMath::getInstance()->add1ToIntegerString($n);
}
} else {
return null;
}
$address = null;
if ($n >= 0) {
if ($positive) {
$start = Factory::parseAddressString($this->getComparableStartString());
$address = $start->getAddressAtOffset($n);
} else {
$end = Factory::parseAddressString($this->getComparableEndString());
$address = $end->getAddressAtOffset($n + 1);
$address = $end->getAddressAtOffset($nPlus1);
}
if ($address === null) {

View file

@ -7,6 +7,7 @@ use IPLib\Address\IPv4;
use IPLib\Address\IPv6;
use IPLib\Address\Type as AddressType;
use IPLib\ParseStringFlag;
use IPLib\Service\BinaryMath;
/**
* Represents an address range in pattern format (only ending asterisks are supported).
@ -304,7 +305,21 @@ class Pattern extends AbstractRange
$maxPrefix = $fromAddress::getNumberOfBits();
$prefix = $this->getNetworkPrefix();
return pow(2, ($maxPrefix - $prefix));
return pow(2, $maxPrefix - $prefix);
}
/**
* {@inheritdoc}
*
* @see \IPLib\Range\RangeInterface::getExactSize()
*/
public function getExactSize()
{
$fromAddress = $this->fromAddress;
$maxPrefix = $fromAddress::getNumberOfBits();
$prefix = $this->getNetworkPrefix();
return BinaryMath::getInstance()->pow2string($maxPrefix - $prefix);
}
/**

View file

@ -46,11 +46,12 @@ interface RangeInterface
/**
* Get the address at a certain offset of this range.
*
* @param int $n the offset of the address (support negative offset)
* @param int|numeric-string $n the offset of the address (support negative offset)
*
* @return \IPLib\Address\AddressInterface|null return NULL if $n is not an integer or if the offset out of range
* @return \IPLib\Address\AddressInterface|null return NULL if $n is neither an integer nor a string containing a valid integer, or if the offset out of range
*
* @since 1.15.0
* @since 1.21.0 $n can also be a numeric string
*
* @example passing 256 to the range 127.0.0.0/16 will result in 127.0.1.0
* @example passing -1 to the range 127.0.1.0/16 will result in 127.0.255.255
@ -150,14 +151,23 @@ interface RangeInterface
public function getReverseDNSLookupName();
/**
* Get the count of addresses this IP range contains.
* Get the count of addresses contained in this IP range (possibly approximated).
*
* @return int|float Return float as for huge IPv6 networks, int is not enough
* @return int|float If the number of addresses exceeds PHP_INT_MAX a float containing an approximation will be returned
*
* @since 1.16.0
*/
public function getSize();
/**
* Get the exact count of addresses contained in this IP range.
*
* @return int|numeric-string If the number of addresses exceeds PHP_INT_MAX a string containing the exact number of addresses will be returned
*
* @since 1.21.0
*/
public function getExactSize();
/**
* Get the "network prefix", that is how many bits of the address are dedicated to the network portion.
*

View file

@ -237,6 +237,16 @@ class Single extends AbstractRange
return 1;
}
/**
* {@inheritdoc}
*
* @see \IPLib\Range\RangeInterface::getExactSize()
*/
public function getExactSize()
{
return 1;
}
/**
* {@inheritdoc}
*

View file

@ -7,6 +7,7 @@ use IPLib\Address\IPv4;
use IPLib\Address\Type as AddressType;
use IPLib\Factory;
use IPLib\ParseStringFlag;
use IPLib\Service\BinaryMath;
/**
* Represents an address range in subnet format (eg CIDR).
@ -348,6 +349,20 @@ class Subnet extends AbstractRange
$maxPrefix = $fromAddress::getNumberOfBits();
$prefix = $this->getNetworkPrefix();
return pow(2, ($maxPrefix - $prefix));
return pow(2, $maxPrefix - $prefix);
}
/**
* {@inheritdoc}
*
* @see \IPLib\Range\RangeInterface::getExactSize()
*/
public function getExactSize()
{
$fromAddress = $this->fromAddress;
$maxPrefix = $fromAddress::getNumberOfBits();
$prefix = $this->getNetworkPrefix();
return BinaryMath::getInstance()->pow2string($maxPrefix - $prefix);
}
}

View file

@ -120,29 +120,29 @@ class Type
case static::T_UNSPECIFIED:
return 'Unspecified/unknown address';
case static::T_RESERVED:
return 'Reserved/internal use only';
return 'Reserved/internal use only';
case static::T_THISNETWORK:
return 'Refer to source hosts on "this" network';
return 'Refer to source hosts on "this" network';
case static::T_LOOPBACK:
return 'Internet host loopback address';
return 'Internet host loopback address';
case static::T_ANYCASTRELAY:
return 'Relay anycast address';
return 'Relay anycast address';
case static::T_LIMITEDBROADCAST:
return '"Limited broadcast" destination address';
return '"Limited broadcast" destination address';
case static::T_MULTICAST:
return 'Multicast address assignments - Indentify a group of interfaces';
return 'Multicast address assignments - Indentify a group of interfaces';
case static::T_LINKLOCAL:
return '"Link local" address, allocated for communication between hosts on a single link';
return '"Link local" address, allocated for communication between hosts on a single link';
case static::T_LINKLOCAL_UNICAST:
return 'Link local unicast / Linked-scoped unicast';
case static::T_DISCARDONLY:
return 'Discard only';
return 'Discard only';
case static::T_DISCARD:
return 'Discard';
return 'Discard';
case static::T_PRIVATENETWORK:
return 'For use in private networks';
return 'For use in private networks';
case static::T_PUBLIC:
return 'Public address';
return 'Public address';
case static::T_CGNAT:
return 'Carrier-grade NAT';
default:

View file

@ -9,6 +9,20 @@ namespace IPLib\Service;
*/
class BinaryMath
{
private static $instance;
/**
* @return \IPLib\Service\BinaryMath
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Trim the leading zeroes from a non-negative integer represented in binary form.
*
@ -97,6 +111,104 @@ class BinaryMath
return $result;
}
/**
* Compute 2 raised to the given exponent.
*
* If the result fits into a native PHP integer, an int is returned.
* If the result exceeds PHP_INT_MAX, a string containing the exact decimal representation is returned.
*
* @param int $exponent The non-negative exponent
*
* @return int|string
*/
public function pow2string($exponent)
{
if ($exponent < PHP_INT_SIZE * 8 - 1) {
return 1 << $exponent;
}
$digits = array(1);
for ($i = 0; $i < $exponent; $i++) {
$carry = 0;
foreach ($digits as $index => $digit) {
$product = $digit * 2 + $carry;
$digits[$index] = $product % 10;
$carry = (int) ($product / 10);
}
if ($carry !== 0) {
$digits[] = $carry;
}
}
return implode('', array_reverse($digits));
}
/**
* @param numeric-string|mixed $value
*
* @return string empty string if $value is not a valid numeric string
*/
public function normalizeIntegerString($value)
{
if (!is_string($value) || $value === '') {
return '';
}
$sign = $value[0];
if ($sign === '-' || $sign === '+') {
$value = substr($value, 1);
}
$matches = null;
if (!preg_match('/^0*([0-9]+)$/', $value, $matches)) {
return '';
}
return ($sign === '-' && $matches[1] !== '0' ? $sign : '') . $matches[1];
}
/**
* @param numeric-string $value a string that has been normalized with normalizeIntegerString()
*
* @return string
*/
public function add1ToIntegerString($value)
{
if ($value[0] === '-') {
if ($value === '-1') {
return '0';
}
$digits = str_split(substr($value, 1));
$i = count($digits) - 1;
while ($i >= 0) {
if ($digits[$i] !== '0') {
$digits[$i] = (string) ((int) $digits[$i] - 1);
break;
}
$digits[$i] = '9';
$i--;
}
$imploded = implode('', $digits);
if ($imploded[0] === '0') {
$imploded = substr($imploded, 1);
}
return '-' . $imploded;
}
$digits = str_split($value);
$carry = 1;
for ($i = count($digits) - 1; $i >= 0; $i--) {
$sum = (int) $digits[$i] + $carry;
$digits[$i] = (string) ($sum % 10);
$carry = (int) ($sum / 10);
if ($carry === 0) {
break;
}
if ($i === 0) {
array_unshift($digits, (string) $carry);
}
}
return implode('', $digits);
}
/**
* Zero-padding of two non-negative integers represented in binary form, so that they have the same length.
*

View file

@ -0,0 +1,253 @@
<?php
namespace IPLib\Service;
use InvalidArgumentException;
/**
* @internal
*
* @readonly
*/
class NumberInChunks
{
const CHUNKSIZE_BYTES = 8;
const CHUNKSIZE_WORDS = 16;
/**
* @var bool
*/
public $negative;
/**
* @var int[]
*/
public $chunks;
/**
* @var int
*/
public $chunkSize;
/**
* @param bool $negative
* @param int[] $chunks
* @param int $chunkSize
*/
public function __construct($negative, array $chunks, $chunkSize)
{
$this->negative = $negative;
$this->chunks = $chunks;
$this->chunkSize = $chunkSize;
}
/**
* @throws \InvalidArgumentException if $other has a $chunkSize that's not the same as the $chunkSize of this
*
* @return \IPLib\Service\NumberInChunks
*/
public function negate()
{
return new self($this->chunks === array(0) ? false : !$this->negative, $this->chunks, $this->chunkSize);
}
/**
* @throws \InvalidArgumentException if $other has a $chunkSize that's not the same as the $chunkSize of this
*
* @return \IPLib\Service\NumberInChunks
*/
public function add(NumberInChunks $that)
{
if ($this->chunkSize !== $that->chunkSize) {
throw new InvalidArgumentException('Incompatible chunk size');
}
if ($this->negative === $that->negative) {
return new self($this->negative, self::addChunks($this->chunks, $that->chunks, $this->chunkSize), $this->chunkSize);
}
if ($that->negative) {
list($negative, $chunks) = self::substractChunks($this->chunks, $that->chunks, $this->chunkSize);
} else {
list($negative, $chunks) = self::substractChunks($that->chunks, $this->chunks, $this->chunkSize);
}
return new self($negative, $chunks, $this->chunkSize);
}
/**
* @param int $int
* @param int $chunkSize
*
* @return \IPLib\Service\NumberInChunks
*/
public static function fromInteger($int, $chunkSize)
{
if ($int === 0) {
return new self(false, array(0), $chunkSize);
}
$negative = $int < 0;
if ($negative) {
$positiveInt = -$int;
if (is_float($positiveInt)) { // -PHP_INT_MIN is bigger than PHP_INT_MAX
return self::fromNumericString((string) $int, $chunkSize);
}
$int = $positiveInt;
}
$bitMask = (1 << $chunkSize) - 1;
$chunks = array();
while ($int !== 0) {
$chunks[] = $int & $bitMask;
$int >>= $chunkSize;
}
return new self($negative, array_reverse($chunks), $chunkSize);
}
/**
* @param string $numericString a string normalized with BinaryMath::normalizeIntegerString()
* @param int $chunkSize
*
* @return \IPLib\Service\NumberInChunks
*/
public static function fromNumericString($numericString, $chunkSize)
{
if ($numericString === '0') {
return new self(false, array(0), $chunkSize);
}
$negative = $numericString[0] === '-';
if ($negative) {
$numericString = substr($numericString, 1);
}
$chunks = array();
while ($numericString !== '0') {
$chunks[] = self::modulo($numericString, $chunkSize);
$numericString = self::divide($numericString, $chunkSize);
}
return new self($negative, array_reverse($chunks), $chunkSize);
}
/**
* @param string $numericString
* @param int $chunkSize
*
* @return int
*/
private static function modulo($numericString, $chunkSize)
{
$divisor = 1 << $chunkSize;
$carry = 0;
$len = strlen($numericString);
for ($i = 0; $i < $len; $i++) {
$digit = (int) $numericString[$i];
$carry = ($carry * 10 + $digit) % $divisor;
}
return $carry;
}
/**
* @param string $numericString
* @param int $chunkSize
*
* @return string
*/
private static function divide($numericString, $chunkSize)
{
$divisor = 1 << $chunkSize;
$quotient = '';
$carry = 0;
$len = strlen($numericString);
for ($i = 0; $i < $len; $i++) {
$digit = (int) $numericString[$i];
$value = $carry * 10 + $digit;
$quotient .= (string) ($value >> $chunkSize);
$carry = $value % $divisor;
}
return ltrim($quotient, '0') ?: '0';
}
/**
* @param int[] $addend1
* @param int[] $addend2
* @param int $chunkSize
*
* @return int[]
*/
private static function addChunks(array $addend1, array $addend2, $chunkSize)
{
$divisor = 1 << $chunkSize;
$result = array();
$carry = 0;
while ($addend1 !== array() || $addend2 !== array()) {
$sum = $carry + (array_pop($addend1) ?: 0) + (array_pop($addend2) ?: 0);
$result[] = $sum % $divisor;
$carry = $sum >> $chunkSize;
}
if ($carry !== 0) {
$result[] = $carry;
}
return array_reverse($result);
}
/**
* @param int[] $minuend
* @param int[] $subtrahend
* @param int $chunkSize
*
* @return array
*/
private static function substractChunks(array $minuend, array $subtrahend, $chunkSize)
{
$minuendCount = count($minuend);
$subtrahendCount = count($subtrahend);
if ($minuendCount > $subtrahendCount) {
$count = $minuendCount;
$negative = false;
} elseif ($minuendCount < $subtrahendCount) {
$count = $subtrahendCount;
$negative = true;
} else {
$count = $minuendCount;
$negative = false;
for ($i = 0; $i < $count; $i++) {
$delta = $minuend[$i] - $subtrahend[$i];
if ($delta === 0) {
continue;
}
if ($delta < 0) {
$negative = true;
}
break;
}
}
if ($negative) {
list($minuend, $subtrahend) = array($subtrahend, $minuend);
}
$subtrahend = array_pad($subtrahend, -$count, 0);
$borrowValue = 1 << $chunkSize;
$result = array();
$borrow = 0;
for ($i = $count - 1; $i >= 0; $i--) {
$value = $minuend[$i] - $subtrahend[$i] - $borrow;
if ($value < 0) {
$value += $borrowValue;
$borrow = 1;
} else {
$borrow = 0;
}
$result[] = $value;
}
while (isset($result[1])) {
$value = array_pop($result);
if ($value !== 0) {
$result[] = $value;
break;
}
}
return array($negative, array_reverse($result));
}
}

View file

@ -50,7 +50,7 @@ class RangesFromBoundaryCalculator
*/
public function __construct($numBits)
{
$this->math = new BinaryMath();
$this->math = BinaryMath::getInstance();
$this->setNumBits($numBits);
}