mirror of
https://github.com/PrivateBin/PrivateBin.git
synced 2026-01-23 02:35:23 +00:00
Merge pull request #1711 from PrivateBin/1.7-backport-2.0.3
backport security fixes for 1.7
This commit is contained in:
commit
0618a9dd74
57 changed files with 1023 additions and 446 deletions
14
.github/workflows/codeql-analysis.yml
vendored
14
.github/workflows/codeql-analysis.yml
vendored
|
|
@ -18,6 +18,10 @@ on:
|
|||
schedule:
|
||||
- cron: '28 22 * * 5'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
|
|
@ -26,18 +30,18 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
language: [ 'actions', 'javascript' ]
|
||||
# CodeQL supports [ 'actions', 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
|
@ -46,4 +50,4 @@ jobs:
|
|||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
|
|
|||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
|
|
@ -4,12 +4,16 @@ on:
|
|||
push:
|
||||
tags: '[0-9]+.[0-9]?[0-9]?[0-9]?.?[0-9]+'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
draft:
|
||||
permissions:
|
||||
contents: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch changelog from tag
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
sparse-checkout: CHANGELOG.md
|
||||
sparse-checkout-cone-mode: false
|
||||
|
|
|
|||
16
.github/workflows/snyk-scan.yml
vendored
16
.github/workflows/snyk-scan.yml
vendored
|
|
@ -8,13 +8,23 @@ on:
|
|||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
# https://github.com/snyk/actions/tree/master/php
|
||||
snyk-php:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository == 'PrivateBin/PrivateBin' }}
|
||||
if: |
|
||||
github.repository == 'PrivateBin/PrivateBin' && (
|
||||
github.event.pull_request.author_association == 'COLLABORATOR' ||
|
||||
github.event.pull_request.author_association == 'CONTRIBUTOR' ||
|
||||
github.event.pull_request.author_association == 'MEMBER' ||
|
||||
github.event.pull_request.author_association == 'OWNER' )
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Install Google Cloud Storage
|
||||
run: composer require --no-update google/cloud-storage && composer update --no-dev
|
||||
- name: Run Snyk to check for vulnerabilities
|
||||
|
|
@ -25,6 +35,6 @@ jobs:
|
|||
with:
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
|
|
|||
1
.github/workflows/test-results.yml
vendored
1
.github/workflows/test-results.yml
vendored
|
|
@ -5,6 +5,7 @@ on:
|
|||
workflows: ["Tests"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
|
|
|||
108
.github/workflows/tests.yml
vendored
108
.github/workflows/tests.yml
vendored
|
|
@ -1,15 +1,18 @@
|
|||
name: Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
|
||||
Composer:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
- name: Validate composer.json and composer.lock
|
||||
run: composer validate
|
||||
- name: Install dependencies
|
||||
|
|
@ -36,7 +39,7 @@ jobs:
|
|||
|
||||
# let's get started!
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# cache PHP extensions
|
||||
- name: Setup cache environment
|
||||
|
|
@ -106,20 +109,111 @@ jobs:
|
|||
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results (PHP ${{ matrix.php-versions }})
|
||||
path: tst/results.xml
|
||||
|
||||
PHPunitConfigCombinations:
|
||||
name: PHP configuration combination unit tests
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
php-version: '8.4'
|
||||
extensions: gd, sqlite3
|
||||
extensions-cache-key-name: phpextensions
|
||||
|
||||
steps:
|
||||
|
||||
# let's get started!
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
|
||||
# cache PHP extensions
|
||||
- name: Setup cache environment
|
||||
id: extcache
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php-version }}
|
||||
extensions: ${{ env.extensions }}
|
||||
key: ${{ runner.os }}-${{ env.extensions-cache-key }}
|
||||
|
||||
- name: Cache extensions
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.extcache.outputs.dir }}
|
||||
key: ${{ steps.extcache.outputs.key }}
|
||||
restore-keys: ${{ runner.os }}-${{ env.extensions-cache-key }}
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php-version }}
|
||||
extensions: ${{ env.extensions }}
|
||||
|
||||
# Setup GitHub CI PHP problem matchers
|
||||
# https://github.com/shivammathur/setup-php#problem-matchers
|
||||
- name: Setup problem matchers for PHP
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/php.json"
|
||||
|
||||
- name: Setup problem matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
# composer cache
|
||||
- name: Remove composer lock
|
||||
run: rm composer.lock
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
# http://man7.org/linux/man-pages/man1/date.1.html
|
||||
# https://github.com/actions/cache#creating-a-cache-key
|
||||
- name: Get Date
|
||||
id: get-date
|
||||
run: echo "date=$(/bin/date -u "+%Y%m%d")" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: "${{ steps.composer-cache.outputs.dir }}"
|
||||
key: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }}"
|
||||
restore-keys: "${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-"
|
||||
|
||||
# composer installation
|
||||
- name: Unset platform requirement
|
||||
run: composer config --unset platform
|
||||
|
||||
- name: Setup PHPunit
|
||||
run: composer install -n
|
||||
|
||||
- name: Install Google Cloud Storage
|
||||
run: composer require google/cloud-storage
|
||||
|
||||
# testing
|
||||
- name: Generate configuration combination unit tests
|
||||
run: bin/configuration-test-generator
|
||||
|
||||
- name: Run unit tests
|
||||
run: ../vendor/bin/phpunit --no-coverage --log-junit results.xml ConfigurationCombinationsTest.php
|
||||
working-directory: tst
|
||||
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results
|
||||
path: tst/results.xml
|
||||
|
||||
Mocha:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '18'
|
||||
cache: 'npm'
|
||||
|
|
@ -138,7 +232,7 @@ jobs:
|
|||
|
||||
- name: Upload Test Results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results (Mocha)
|
||||
path: js/mocha-results.xml
|
||||
|
|
@ -148,7 +242,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Event File
|
||||
path: "${{ github.event_path }}"
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -25,6 +25,7 @@ vendor/**/tst
|
|||
vendor/**/tests
|
||||
vendor/**/build_phar.php
|
||||
!vendor/**/*.php
|
||||
vendor/bin/**
|
||||
|
||||
# Ignore local node modules, unit testing logs, api docs and IDE project files
|
||||
js/node_modules/
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@ coding_style:
|
|||
additive: false
|
||||
concatenation: true
|
||||
build:
|
||||
image: default-bionic
|
||||
environment:
|
||||
php:
|
||||
version: 7.4
|
||||
version: 8.2
|
||||
tests:
|
||||
override:
|
||||
-
|
||||
command: 'composer require google/cloud-storage && cd tst && ../vendor/bin/phpunit'
|
||||
- command: 'composer require google/cloud-storage && cd tst && XDEBUG_MODE=coverage ../vendor/bin/phpunit'
|
||||
coverage:
|
||||
file: 'tst/log/coverage-clover.xml'
|
||||
format: 'clover'
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
# Badges
|
||||
|
||||
[](https://travis-ci.org/PrivateBin/PrivateBin) [](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/build-status/master)
|
||||
[](https://www.codacy.com/app/PrivateBin/PrivateBin)
|
||||
[](https://codeclimate.com/github/PrivateBin/PrivateBin)
|
||||
[](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/build-status/master) [](https://codeclimate.com/github/PrivateBin/PrivateBin)
|
||||
[](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
|
||||
[](https://insight.sensiolabs.com/projects/57c9e74e-c6f9-4de6-a876-df66ec2ea1ff)
|
||||
[](https://www.codacy.com/app/PrivateBin/PrivateBin)
|
||||
[](https://codeclimate.com/github/PrivateBin/PrivateBin/coverage) [](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
|
||||
[](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
|
||||
|
||||
[](https://www.browserstack.com/)
|
||||
|
|
|
|||
10
CHANGELOG.md
10
CHANGELOG.md
|
|
@ -1,5 +1,15 @@
|
|||
# PrivateBin version history
|
||||
|
||||
## 1.7.9 (not yet released)
|
||||
* CHANGED: Upgrading libraries to: base-x 5.0.1, bootstrap 5.3.8, DOMpurify 3.2.7, ip-lib 1.21.0 & kjua 0.10.0
|
||||
* CHANGED: Refactored jQuery DOM element creation into plain JavaScript
|
||||
* FIXED: Prevent arbitrary PHP file inclusion when enabling template switching
|
||||
* FIXED: Malicious filename can be used for self-XSS / HTML injection locally for users
|
||||
* FIXED: Sanitize file name in attachment size hint
|
||||
* FIXED: Unable to create a new paste from the cloned one when a JSON file attached (#1585)
|
||||
* FIXED: traffic limiter not working when using Filesystem storage and PHP opcache
|
||||
* FIXED: Configuration combinations test errors
|
||||
|
||||
## 1.7.8 (2025-06-30)
|
||||
* FIXED: Duplicate attachment for every comment (#1577)
|
||||
* FIXED: Attachments with empty file names (#1577)
|
||||
|
|
|
|||
|
|
@ -536,7 +536,8 @@ EOT;
|
|||
break;
|
||||
case 'Delete':
|
||||
$code .= PHP_EOL . <<<'EOT'
|
||||
$this->_model->create(Helper::getPasteId(), Helper::getPaste());
|
||||
$paste = Helper::getPaste();
|
||||
$this->_model->create(Helper::getPasteId(), $paste);
|
||||
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
|
||||
$_GET['pasteid'] = Helper::getPasteId();
|
||||
$_GET['deletetoken'] = hash_hmac('sha256', Helper::getPasteId(), $this->_model->read(Helper::getPasteId())['meta']['salt']);
|
||||
|
|
@ -574,7 +575,7 @@ EOT;
|
|||
$code .= <<<'EOT'
|
||||
|
||||
$this->assertMatchesRegularExpression(
|
||||
'#<div[^>]*id="status"[^>]*>.*Paste was properly deleted[^<]*</div>#s',
|
||||
'#<div[^>]*id="status"[^>]*>.*Paste was properly deleted[^<]*(<button|<\/div>)#s',
|
||||
$content,
|
||||
'outputs deleted status correctly'
|
||||
);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@ on:
|
|||
schedule:
|
||||
- cron: '45 16 * * 1'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
name: Codacy Security Scan
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
"require" : {
|
||||
"php": "^7.3 || ^8.0",
|
||||
"jdenticon/jdenticon": "1.0.2",
|
||||
"mlocati/ip-lib": "1.20.0",
|
||||
"mlocati/ip-lib": "1.21.0",
|
||||
"symfony/polyfill-php80": "1.31.0",
|
||||
"yzalis/identicon": "2.0.0"
|
||||
},
|
||||
|
|
|
|||
152
composer.lock
generated
152
composer.lock
generated
|
|
@ -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": "6c7e6dea19e8bfd5641b220cb68c4b65",
|
||||
"content-hash": "a6501ecd3d80fece24f1c78e49df7217",
|
||||
"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.0",
|
||||
"version": "1.13.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/myclabs/DeepCopy.git",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
|
||||
"reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
|
||||
"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.0"
|
||||
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -393,7 +393,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-02-12T12:17:51+00:00"
|
||||
"time": "2025-08-01T08:46:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
|
|
@ -890,16 +890,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.22",
|
||||
"version": "9.6.29",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
|
||||
"reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
|
||||
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
|
||||
"reference": "9ecfec57835a5581bc888ea7e13b51eb55ab9dd3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -910,7 +910,7 @@
|
|||
"ext-mbstring": "*",
|
||||
"ext-xml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"myclabs/deep-copy": "^1.12.1",
|
||||
"myclabs/deep-copy": "^1.13.4",
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=7.3",
|
||||
|
|
@ -921,11 +921,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",
|
||||
|
|
@ -973,7 +973,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.22"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.29"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
|
@ -984,12 +984,20 @@
|
|||
"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/phpunit/phpunit",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-05T13:48:26+00:00"
|
||||
"time": "2025-09-24T06:29:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
@ -1160,16 +1168,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": {
|
||||
|
|
@ -1222,15 +1230,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",
|
||||
|
|
@ -1420,16 +1440,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": {
|
||||
|
|
@ -1485,28 +1505,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": {
|
||||
|
|
@ -1549,15 +1581,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",
|
||||
|
|
@ -1730,16 +1774,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": {
|
||||
|
|
@ -1781,15 +1825,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",
|
||||
|
|
@ -2017,5 +2073,5 @@
|
|||
"platform-overrides": {
|
||||
"php": "7.3"
|
||||
},
|
||||
"plugin-api-version": "2.3.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
|||
5
css/bootstrap5/bootstrap-5.3.3.css
vendored
5
css/bootstrap5/bootstrap-5.3.3.css
vendored
File diff suppressed because one or more lines are too long
5
css/bootstrap5/bootstrap-5.3.8.css
vendored
Normal file
5
css/bootstrap5/bootstrap-5.3.8.css
vendored
Normal file
File diff suppressed because one or more lines are too long
5
css/bootstrap5/bootstrap.rtl-5.3.3.css
vendored
5
css/bootstrap5/bootstrap.rtl-5.3.3.css
vendored
File diff suppressed because one or more lines are too long
5
css/bootstrap5/bootstrap.rtl-5.3.8.css
vendored
Normal file
5
css/bootstrap5/bootstrap.rtl-5.3.8.css
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -22,12 +22,20 @@ for more information.
|
|||
### Minimal Requirements
|
||||
|
||||
- PHP version 7.3 or above
|
||||
- GD extension (when using identicon or vizhash icons, jdenticon works without it)
|
||||
- zlib extension
|
||||
- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php)
|
||||
- ability to create files and folders in the installation directory and the PATH
|
||||
defined in index.php
|
||||
- A web browser with JavaScript and (optional) WebAssembly support
|
||||
- PHP with zlib extension
|
||||
- some disk space and the capability to create files and folders in the
|
||||
installation directory and the `PATH` defined in index.php
|
||||
- A web browser with JavaScript support enabled
|
||||
|
||||
### Optional Requirements
|
||||
|
||||
- PHP with GD extension (when using identicon or vizhash icons, jdenticon works
|
||||
without it) and OPcache (for better performance)
|
||||
- a database supported by [PHP PDO](https://php.net/manual/book.pdo.php) and the
|
||||
PHP PDO extension (when using database storage)
|
||||
- a Ceph cluster with Rados gateway or AWS S3 storage (when using S3 storage)
|
||||
- Google Cloud Storage (when using GCP storage)
|
||||
- A web browser with WebAssembly support
|
||||
|
||||
## Hardening and Security
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Please have a look at these questions *before* opening an issue in this repo.
|
||||
|
||||
## [Installation guide](https://github.com/PrivateBin/PrivateBin/blob/master/doc/Installation.md#installation)
|
||||
## [Installation guide](Installation.md#installation)
|
||||
|
||||
Minimal requirements, hardening and securing your installation and initial
|
||||
configuration.
|
||||
|
|
@ -26,12 +26,12 @@ How to help translate PrivateBin and technical background on it's implementation
|
|||
|
||||
Know how for participating in PrivateBins development.
|
||||
|
||||
### [Generating Source Code Documentation](https://github.com/PrivateBin/PrivateBin/blob/master/doc/Generating%20Source%20Code%20Documentation.md#generating-source-code-documentation)
|
||||
### [Generating Source Code Documentation](Generating%20Source%20Code%20Documentation.md#generating-source-code-documentation)
|
||||
|
||||
How to generate the source code API documentation, as found on the project
|
||||
website for [PHP](https://privatebin.info/codedoc/) and [JS](https://privatebin.info/jsdoc/)
|
||||
|
||||
### [Running Unit Tests](https://github.com/PrivateBin/PrivateBin/blob/master/doc/Running Unit Tests.md#running-all-unit-tests)
|
||||
### [Running Unit Tests](Running%20Unit%20Tests.md#running-all-unit-tests)
|
||||
|
||||
How to run the PHP & JS unit tests, including a brief introduction to property
|
||||
based unit testing.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ The parameters in detail:
|
|||
an accidentally destructive test case in it.
|
||||
- `--read-only` - This image supports running in read-only mode. Only /tmp
|
||||
may be written into.
|
||||
- `-rm` - Remove the container after the run. This saves you doing a cleanup
|
||||
- `--rm` - Remove the container after the run. This saves you doing a cleanup
|
||||
on your docker environment, if you run the image frequently.
|
||||
|
||||
You can also run just the php and javascript test suites instead of both:
|
||||
|
|
|
|||
|
|
@ -7,47 +7,47 @@
|
|||
(function(){
|
||||
this.baseX = function base (ALPHABET) {
|
||||
if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }
|
||||
var BASE_MAP = new Uint8Array(256)
|
||||
for (var j = 0; j < BASE_MAP.length; j++) {
|
||||
const BASE_MAP = new Uint8Array(256)
|
||||
for (let j = 0; j < BASE_MAP.length; j++) {
|
||||
BASE_MAP[j] = 255
|
||||
}
|
||||
for (var i = 0; i < ALPHABET.length; i++) {
|
||||
var x = ALPHABET.charAt(i)
|
||||
var xc = x.charCodeAt(0)
|
||||
for (let i = 0; i < ALPHABET.length; i++) {
|
||||
const x = ALPHABET.charAt(i)
|
||||
const xc = x.charCodeAt(0)
|
||||
if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }
|
||||
BASE_MAP[xc] = i
|
||||
}
|
||||
var BASE = ALPHABET.length
|
||||
var LEADER = ALPHABET.charAt(0)
|
||||
var FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up
|
||||
var iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up
|
||||
const BASE = ALPHABET.length
|
||||
const LEADER = ALPHABET.charAt(0)
|
||||
const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up
|
||||
const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up
|
||||
function encode (source) {
|
||||
if (source instanceof Uint8Array) {
|
||||
} else if (ArrayBuffer.isView(source)) {
|
||||
// eslint-disable-next-line no-empty
|
||||
if (source instanceof Uint8Array) { } else if (ArrayBuffer.isView(source)) {
|
||||
source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength)
|
||||
} else if (Array.isArray(source)) {
|
||||
source = Uint8Array.from(source)
|
||||
}
|
||||
if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') }
|
||||
if (source.length === 0) { return '' }
|
||||
// Skip & count leading zeroes.
|
||||
var zeroes = 0
|
||||
var length = 0
|
||||
var pbegin = 0
|
||||
var pend = source.length
|
||||
// Skip & count leading zeroes.
|
||||
let zeroes = 0
|
||||
let length = 0
|
||||
let pbegin = 0
|
||||
const pend = source.length
|
||||
while (pbegin !== pend && source[pbegin] === 0) {
|
||||
pbegin++
|
||||
zeroes++
|
||||
}
|
||||
// Allocate enough space in big-endian base58 representation.
|
||||
var size = ((pend - pbegin) * iFACTOR + 1) >>> 0
|
||||
var b58 = new Uint8Array(size)
|
||||
// Process the bytes.
|
||||
// Allocate enough space in big-endian base58 representation.
|
||||
const size = ((pend - pbegin) * iFACTOR + 1) >>> 0
|
||||
const b58 = new Uint8Array(size)
|
||||
// Process the bytes.
|
||||
while (pbegin !== pend) {
|
||||
var carry = source[pbegin]
|
||||
// Apply "b58 = b58 * 256 + ch".
|
||||
var i = 0
|
||||
for (var it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
|
||||
let carry = source[pbegin]
|
||||
// Apply "b58 = b58 * 256 + ch".
|
||||
let i = 0
|
||||
for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
|
||||
carry += (256 * b58[it1]) >>> 0
|
||||
b58[it1] = (carry % BASE) >>> 0
|
||||
carry = (carry / BASE) >>> 0
|
||||
|
|
@ -56,38 +56,42 @@ this.baseX = function base (ALPHABET) {
|
|||
length = i
|
||||
pbegin++
|
||||
}
|
||||
// Skip leading zeroes in base58 result.
|
||||
var it2 = size - length
|
||||
// Skip leading zeroes in base58 result.
|
||||
let it2 = size - length
|
||||
while (it2 !== size && b58[it2] === 0) {
|
||||
it2++
|
||||
}
|
||||
// Translate the result into a string.
|
||||
var str = LEADER.repeat(zeroes)
|
||||
// Translate the result into a string.
|
||||
let str = LEADER.repeat(zeroes)
|
||||
for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }
|
||||
return str
|
||||
}
|
||||
function decodeUnsafe (source) {
|
||||
if (typeof source !== 'string') { throw new TypeError('Expected String') }
|
||||
if (source.length === 0) { return new Uint8Array() }
|
||||
var psz = 0
|
||||
// Skip and count leading '1's.
|
||||
var zeroes = 0
|
||||
var length = 0
|
||||
let psz = 0
|
||||
// Skip and count leading '1's.
|
||||
let zeroes = 0
|
||||
let length = 0
|
||||
while (source[psz] === LEADER) {
|
||||
zeroes++
|
||||
psz++
|
||||
}
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
var size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.
|
||||
var b256 = new Uint8Array(size)
|
||||
// Process the characters.
|
||||
while (source[psz]) {
|
||||
// Decode character
|
||||
var carry = BASE_MAP[source.charCodeAt(psz)]
|
||||
// Invalid character
|
||||
// Allocate enough space in big-endian base256 representation.
|
||||
const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.
|
||||
const b256 = new Uint8Array(size)
|
||||
// Process the characters.
|
||||
while (psz < source.length) {
|
||||
// Find code of next character
|
||||
const charCode = source.charCodeAt(psz)
|
||||
// Base map can not be indexed using char code
|
||||
if (charCode > 255) { return }
|
||||
// Decode character
|
||||
let carry = BASE_MAP[charCode]
|
||||
// Invalid character
|
||||
if (carry === 255) { return }
|
||||
var i = 0
|
||||
for (var it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
|
||||
let i = 0
|
||||
for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
|
||||
carry += (BASE * b256[it3]) >>> 0
|
||||
b256[it3] = (carry % 256) >>> 0
|
||||
carry = (carry / 256) >>> 0
|
||||
|
|
@ -96,27 +100,27 @@ this.baseX = function base (ALPHABET) {
|
|||
length = i
|
||||
psz++
|
||||
}
|
||||
// Skip leading zeroes in b256.
|
||||
var it4 = size - length
|
||||
// Skip leading zeroes in b256.
|
||||
let it4 = size - length
|
||||
while (it4 !== size && b256[it4] === 0) {
|
||||
it4++
|
||||
}
|
||||
var vch = new Uint8Array(zeroes + (size - it4))
|
||||
var j = zeroes
|
||||
const vch = new Uint8Array(zeroes + (size - it4))
|
||||
let j = zeroes
|
||||
while (it4 !== size) {
|
||||
vch[j++] = b256[it4++]
|
||||
}
|
||||
return vch
|
||||
}
|
||||
function decode (string) {
|
||||
var buffer = decodeUnsafe(string)
|
||||
const buffer = decodeUnsafe(string)
|
||||
if (buffer) { return buffer }
|
||||
throw new Error('Non-base' + BASE + ' character')
|
||||
}
|
||||
return {
|
||||
encode: encode,
|
||||
decodeUnsafe: decodeUnsafe,
|
||||
decode: decode
|
||||
encode,
|
||||
decodeUnsafe,
|
||||
decode
|
||||
}
|
||||
}
|
||||
}).call(this);
|
||||
6
js/bootstrap-5.3.3.js
vendored
6
js/bootstrap-5.3.3.js
vendored
File diff suppressed because one or more lines are too long
6
js/bootstrap-5.3.8.js
vendored
Normal file
6
js/bootstrap-5.3.8.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -16,8 +16,8 @@ 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.baseX = require('./base-x-4.0.0').baseX;
|
||||
global.DOMPurify = require('./purify-3.3.0');
|
||||
global.baseX = require('./base-x-5.0.1').baseX;
|
||||
global.Legacy = require('./legacy').Legacy;
|
||||
require('./bootstrap-3.4.1');
|
||||
require('./privatebin');
|
||||
|
|
|
|||
2
js/kjua-0.10.0.js
Normal file
2
js/kjua-0.10.0.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -106,8 +106,8 @@
|
|||
return window.isSecureContext;
|
||||
}
|
||||
|
||||
// HTTP is obviously insecure
|
||||
if (window.location.protocol !== 'http:') {
|
||||
// HTTPS is considered secure
|
||||
if (window.location.protocol === 'https:') {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -246,6 +246,11 @@
|
|||
*/
|
||||
me.init = function()
|
||||
{
|
||||
// prevent early init
|
||||
if (typeof document === 'undefined' || typeof navigator === 'undefined' || typeof window === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent bots from viewing a paste and potentially deleting data
|
||||
// when burn-after-reading is set
|
||||
if (isBadBot()) {
|
||||
|
|
|
|||
113
js/privatebin.js
113
js/privatebin.js
|
|
@ -10,7 +10,7 @@
|
|||
* @namespace
|
||||
*/
|
||||
|
||||
// global Base64, DOMPurify, FileReader, RawDeflate, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua
|
||||
// global Base64, DOMPurify, FileReader, baseX, bootstrap, RawDeflate, history, navigator, prettyPrint, prettyPrintOne, showdown, kjua
|
||||
|
||||
jQuery.fn.draghover = function() {
|
||||
'use strict';
|
||||
|
|
@ -975,7 +975,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
*
|
||||
* @private
|
||||
*/
|
||||
let base58 = new baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
||||
const base58 = new baseX('123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz');
|
||||
|
||||
/**
|
||||
* convert UTF-8 string stored in a DOMString to a standard UTF-16 DOMString
|
||||
|
|
@ -3028,7 +3028,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
attachmentLink.attr('download', fileName);
|
||||
|
||||
const fileSize = Helper.formatBytes(decodedData.length);
|
||||
template.append(`(${fileName}, ${fileSize})`);
|
||||
const fileInfo = document.createTextNode(` (${fileName}, ${fileSize})`);
|
||||
template[0].appendChild(fileInfo);
|
||||
}
|
||||
|
||||
// sanitize SVG preview
|
||||
|
|
@ -3121,10 +3122,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
* @name AttachmentViewer.printDragAndDropFileNames
|
||||
* @private
|
||||
* @function
|
||||
* @param {array} fileNames
|
||||
* @param {string[]} fileNames
|
||||
*/
|
||||
function printDragAndDropFileNames(fileNames) {
|
||||
$dragAndDropFileNames.html(fileNames.join("<br>"));
|
||||
$dragAndDropFileNames.empty();
|
||||
fileNames.forEach(fileName => {
|
||||
const name = document.createTextNode(fileName);
|
||||
$dragAndDropFileNames[0].appendChild(name);
|
||||
$dragAndDropFileNames[0].appendChild(document.createElement('br'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3323,44 +3329,38 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
const alreadyIncludesCurrentAttachment = $targetElement.find(`[src='${blobUrl}']`).length > 0;
|
||||
|
||||
if (blobUrl && !alreadyIncludesCurrentAttachment) {
|
||||
if (mimeType.match(/^image\//i)) {
|
||||
$targetElement.append(
|
||||
$(document.createElement('img'))
|
||||
.attr('src', blobUrl)
|
||||
.attr('class', 'img-thumbnail')
|
||||
);
|
||||
} else if (mimeType.match(/^video\//i)) {
|
||||
$targetElement.append(
|
||||
$(document.createElement('video'))
|
||||
.attr('controls', 'true')
|
||||
.attr('autoplay', 'true')
|
||||
.attr('class', 'img-thumbnail')
|
||||
|
||||
.append($(document.createElement('source'))
|
||||
.attr('type', mimeType)
|
||||
.attr('src', blobUrl))
|
||||
);
|
||||
} else if (mimeType.match(/^audio\//i)) {
|
||||
$targetElement.append(
|
||||
$(document.createElement('audio'))
|
||||
.attr('controls', 'true')
|
||||
.attr('autoplay', 'true')
|
||||
|
||||
.append($(document.createElement('source'))
|
||||
.attr('type', mimeType)
|
||||
.attr('src', blobUrl))
|
||||
);
|
||||
} else if (mimeType.match(/\/pdf/i)) {
|
||||
if (mimeType.toLowerCase().startsWith('image/')) {
|
||||
const image = document.createElement('img');
|
||||
image.setAttribute('src', blobUrl);
|
||||
image.setAttribute('class', 'img-thumbnail');
|
||||
$targetElement[0].appendChild(image);
|
||||
} else if (mimeType.toLowerCase().startsWith('video/')) {
|
||||
const video = document.createElement('video');
|
||||
video.setAttribute('controls', 'true');
|
||||
video.setAttribute('autoplay', 'true');
|
||||
video.setAttribute('class', 'img-thumbnail');
|
||||
const source = document.createElement('source');
|
||||
source.setAttribute('type', mimeType);
|
||||
source.setAttribute('src', blobUrl);
|
||||
video.appendChild(source);
|
||||
$targetElement[0].appendChild(video);
|
||||
} else if (mimeType.toLowerCase().startsWith('audio/')) {
|
||||
const audio = document.createElement('audio');
|
||||
audio.setAttribute('controls', 'true');
|
||||
audio.setAttribute('autoplay', 'true');
|
||||
const source = document.createElement('source');
|
||||
source.setAttribute('type', mimeType);
|
||||
source.setAttribute('src', blobUrl);
|
||||
audio.appendChild(source);
|
||||
$targetElement[0].appendChild(audio);
|
||||
} else if (mimeType.toLowerCase().endsWith('/pdf')) {
|
||||
const embed = document.createElement('embed');
|
||||
embed.setAttribute('src', blobUrl);
|
||||
embed.setAttribute('type', 'application/pdf');
|
||||
embed.setAttribute('class', 'pdfPreview');
|
||||
// Fallback for browsers, that don't support the vh unit
|
||||
const clientHeight = $(window).height();
|
||||
|
||||
$targetElement.append(
|
||||
$(document.createElement('embed'))
|
||||
.attr('src', blobUrl)
|
||||
.attr('type', 'application/pdf')
|
||||
.attr('class', 'pdfPreview')
|
||||
.css('height', clientHeight)
|
||||
);
|
||||
embed.style.height = window.innerHeight + 'px';
|
||||
$targetElement[0].appendChild(embed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -3638,8 +3638,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
if (nickname.length > 0) {
|
||||
$commentEntry.find('span.nickname').text(nickname);
|
||||
} else {
|
||||
$commentEntry.find('span.nickname').html('<i></i>');
|
||||
I18n._($commentEntry.find('span.nickname i'), 'Anonymous');
|
||||
const anonCommenter = document.createElement('em');
|
||||
anonCommenter.textContent = I18n._('Anonymous');
|
||||
$commentEntry.find('span.nickname')[0].innerHTML = '';
|
||||
$commentEntry.find('span.nickname')[0].appendChild(anonCommenter);
|
||||
}
|
||||
|
||||
// set date
|
||||
|
|
@ -3652,14 +3654,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
// if an avatar is available, display it
|
||||
const icon = comment.getIcon();
|
||||
if (icon) {
|
||||
$commentEntry.find('span.nickname')
|
||||
.before(
|
||||
'<img src="' + icon + '" class="vizhash" /> '
|
||||
);
|
||||
$(document).on('languageLoaded', function () {
|
||||
$commentEntry.find('img.vizhash')
|
||||
.prop('title', I18n._('Avatar generated from IP address'));
|
||||
});
|
||||
const image = document.createElement('img');
|
||||
image.setAttribute('src', icon);
|
||||
image.setAttribute('class', 'vizhash');
|
||||
$commentEntry.find('span.nickname').prepend(' ').prepend(image);
|
||||
}
|
||||
|
||||
// starting point (default value/fallback)
|
||||
|
|
@ -5268,22 +5266,23 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
cipherMessage['attachment'] = attachments.map(attachment => attachment[0]);
|
||||
cipherMessage['attachment_name'] = attachments.map(attachment => attachment[1]);
|
||||
|
||||
cipherMessage['attachment'] = await Promise.all(cipherMessage['attachment'].map(async (attachment) => {
|
||||
cipherMessage['attachment'] = await Promise.all(cipherMessage['attachment'].map(async (attachment, i) => {
|
||||
// we need to retrieve data from blob if browser already parsed it in memory
|
||||
if (typeof attachment === 'string' && attachment.startsWith('blob:')) {
|
||||
Alert.showStatus(
|
||||
[
|
||||
'Retrieving cloned file \'%s\' from memory...',
|
||||
attachment[1]
|
||||
cipherMessage['attachment_name'][i]
|
||||
],
|
||||
'copy'
|
||||
);
|
||||
try {
|
||||
const blobData = await $.ajax({
|
||||
type: 'GET',
|
||||
url: `${attachment}`,
|
||||
url: attachment,
|
||||
processData: false,
|
||||
timeout: 10000,
|
||||
dataType: 'binary',
|
||||
xhrFields: {
|
||||
withCredentials: false,
|
||||
responseType: 'blob'
|
||||
|
|
@ -5493,6 +5492,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
plaintexts[i][1]
|
||||
);
|
||||
}
|
||||
$(document).on('languageLoaded', function () {
|
||||
$('#commentcontainer').find('img.vizhash')
|
||||
.prop('title', I18n._('Avatar generated from IP address'));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
2
js/purify-3.3.0.js
Normal file
2
js/purify-3.3.0.js
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -24,6 +24,8 @@ describe('Prompt', function () {
|
|||
);
|
||||
$.PrivateBin.Model.reset();
|
||||
$.PrivateBin.Model.init();
|
||||
// eslint-disable-next-line global-require
|
||||
global.bootstrap = require('../bootstrap-5.3.8');
|
||||
$.PrivateBin.Prompt.init();
|
||||
$.PrivateBin.Prompt.requestPassword();
|
||||
$('#passworddecrypt').val(password);
|
||||
|
|
@ -39,4 +41,3 @@ describe('Prompt', function () {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -110,17 +110,17 @@ class Configuration
|
|||
),
|
||||
// update this array when adding/changing/removing js files
|
||||
'sri' => array(
|
||||
'js/base-x-4.0.0.js' => 'sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==',
|
||||
'js/base-x-5.0.1.js' => 'sha512-FmhlnjIxQyxkkxQmzf0l6IRGsGbgyCdgqPxypFsEtHMF1naRqaLLo6mcyN5rEaT16nKx1PeJ4g7+07D6gnk/Tg==',
|
||||
'js/base64-1.7.js' => 'sha512-JdwsSP3GyHR+jaCkns9CL9NTt4JUJqm/BsODGmYhBcj5EAPKcHYh+OiMfyHbcDLECe17TL0hjXADFkusAqiYgA==',
|
||||
'js/bootstrap-3.4.1.js' => 'sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==',
|
||||
'js/bootstrap-5.3.3.js' => 'sha512-in2rcOpLTdJ7/pw5qjF4LWHFRtgoBDxXCy49H4YGOcVdGiPaQucGIbOqxt1JvmpvOpq3J/C7VTa0FlioakB2gQ==',
|
||||
'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.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==',
|
||||
'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==',
|
||||
'js/kjua-0.10.0.js' => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==',
|
||||
'js/legacy.js' => 'sha512-iP69buypAHBJOgt7AyDcfaelVxBES9/k3dVfd6hPxTRizVRH2dijEpMWCt1D8OH4FNgytKsDI/J7+9y7IgXPaA==',
|
||||
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
|
||||
'js/privatebin.js' => 'sha512-i0l0rh+NCY8Oeg9SxzQREHin6egXJ6sdIC84RTEsBpBNhYGObv8QEdRng1dMERZmw4olVeXx2ZCkusTyT1G+SA==',
|
||||
'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==',
|
||||
'js/privatebin.js' => 'sha512-ehY9hXpKGr1xhUaZbD6n2IyfyUvTVHDtcobY/azlnuOnXmdwgH4dHSGUSNxscyeMxHAktS/9K8UTYyCka4Cnlg==',
|
||||
'js/purify-3.3.0.js' => 'sha512-lsHD5zxs4lu/NDzaaibe27Vd2t7Cy9JQ3qDHUvDfb4oZvKoWDNEhwUY+4bT3R68cGgpgCYp8U1x2ifeVxqurdQ==',
|
||||
'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==',
|
||||
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
|
||||
'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',
|
||||
|
|
|
|||
|
|
@ -210,13 +210,17 @@ class Controller
|
|||
{
|
||||
$templates = $this->_conf->getKey('availabletemplates');
|
||||
$template = $this->_conf->getKey('template');
|
||||
if (!in_array($template, $templates, true)) {
|
||||
$templates[] = $template;
|
||||
}
|
||||
TemplateSwitcher::setAvailableTemplates($templates);
|
||||
TemplateSwitcher::setTemplateFallback($template);
|
||||
|
||||
// force default template, if template selection is disabled and a default is set
|
||||
if (!$this->_conf->getKey('templateselection') && !empty($template)) {
|
||||
$_COOKIE['template'] = $template;
|
||||
setcookie('template', $template, array('SameSite' => 'Lax', 'Secure' => true));
|
||||
// force default template, if template selection is disabled
|
||||
if (!$this->_conf->getKey('templateselection') && array_key_exists('template', $_COOKIE)) {
|
||||
unset($_COOKIE['template']); // ensure value is not re-used in template switcher
|
||||
$expiredInAllTimezones = time() - 86400;
|
||||
setcookie('template', '', array('expires' => $expiredInAllTimezones, 'SameSite' => 'Lax', 'Secure' => true));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -274,6 +274,9 @@ class Filesystem extends AbstractData
|
|||
{
|
||||
switch ($namespace) {
|
||||
case 'purge_limiter':
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php');
|
||||
}
|
||||
return $this->_storeString(
|
||||
$this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php',
|
||||
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . var_export($value, true) . ';'
|
||||
|
|
@ -285,6 +288,9 @@ class Filesystem extends AbstractData
|
|||
);
|
||||
case 'traffic_limiter':
|
||||
$this->_last_cache[$key] = $value;
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($this->_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php');
|
||||
}
|
||||
return $this->_storeString(
|
||||
$this->_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php',
|
||||
'<?php' . PHP_EOL . '$GLOBALS[\'traffic_limiter\'] = ' . var_export($this->_last_cache, true) . ';'
|
||||
|
|
|
|||
|
|
@ -204,16 +204,10 @@ class TrafficLimiter extends AbstractPersistence
|
|||
$now = time();
|
||||
$tl = (int) self::$_store->getValue('traffic_limiter', $hash);
|
||||
self::$_store->purgeValues('traffic_limiter', $now - self::$_limit);
|
||||
if ($tl > 0 && ($tl + self::$_limit >= $now)) {
|
||||
$result = false;
|
||||
} else {
|
||||
$tl = time();
|
||||
$result = true;
|
||||
}
|
||||
if (!self::$_store->setValue((string) $tl, 'traffic_limiter', $hash)) {
|
||||
error_log('failed to store the traffic limiter, it probably contains outdated information');
|
||||
}
|
||||
if ($result) {
|
||||
if ($tl === 0 || ($tl + self::$_limit) < $now) {
|
||||
if (!self::$_store->setValue((string) $now, 'traffic_limiter', $hash)) {
|
||||
error_log('failed to store the traffic limiter, it probably contains outdated information');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
throw new Exception(I18n::_(
|
||||
|
|
|
|||
|
|
@ -59,16 +59,13 @@ class TemplateSwitcher
|
|||
{
|
||||
if (self::isTemplateAvailable($template)) {
|
||||
self::$_templateFallback = $template;
|
||||
|
||||
if (!in_array($template, self::getAvailableTemplates())) {
|
||||
// Add custom template to the available templates list
|
||||
self::$_availableTemplates[] = $template;
|
||||
}
|
||||
} else {
|
||||
error_log('failed to set "' . $template . '" as a fallback, it needs to be added to the list of `availabletemplates` in the configuration file');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get currently loaded template
|
||||
* get user selected template or fallback
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
|
|
@ -76,8 +73,13 @@ class TemplateSwitcher
|
|||
*/
|
||||
public static function getTemplate(): string
|
||||
{
|
||||
$selectedTemplate = self::getSelectedByUserTemplate();
|
||||
return $selectedTemplate ?? self::$_templateFallback;
|
||||
if (array_key_exists('template', $_COOKIE)) {
|
||||
$template = basename($_COOKIE['template']);
|
||||
if (self::isTemplateAvailable($template)) {
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
return self::$_templateFallback;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -101,32 +103,10 @@ class TemplateSwitcher
|
|||
*/
|
||||
public static function isTemplateAvailable(string $template): bool
|
||||
{
|
||||
$available = in_array($template, self::getAvailableTemplates());
|
||||
|
||||
if (!$available && !View::isBootstrapTemplate($template)) {
|
||||
$path = View::getTemplateFilePath($template);
|
||||
$available = file_exists($path);
|
||||
if (in_array($template, self::getAvailableTemplates(), true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $available;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the template selected by user
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
* @return string|null
|
||||
*/
|
||||
private static function getSelectedByUserTemplate(): ?string
|
||||
{
|
||||
$selectedTemplate = null;
|
||||
$templateCookieValue = $_COOKIE['template'] ?? '';
|
||||
|
||||
if (self::isTemplateAvailable($templateCookieValue)) {
|
||||
$selectedTemplate = $templateCookieValue;
|
||||
}
|
||||
|
||||
return $selectedTemplate;
|
||||
error_log('template "' . $template . '" is not in the list of `availabletemplates` in the configuration file');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
36
lib/View.php
36
lib/View.php
|
|
@ -49,39 +49,19 @@ class View
|
|||
*/
|
||||
public function draw($template)
|
||||
{
|
||||
$path = self::getTemplateFilePath($template);
|
||||
if (!file_exists($path)) {
|
||||
throw new Exception('Template ' . $template . ' not found!', 80);
|
||||
$dir = PATH . 'tpl' . DIRECTORY_SEPARATOR;
|
||||
$file = substr($template, 0, 10) === 'bootstrap-' ? 'bootstrap' : $template;
|
||||
$path = $dir . $file . '.php';
|
||||
if (!is_file($path)) {
|
||||
throw new Exception('Template ' . $template . ' not found in file ' . $path . '!', 80);
|
||||
}
|
||||
if (!in_array($path, glob($dir . '*.php', GLOB_NOSORT | GLOB_ERR), true)) {
|
||||
throw new Exception('Template ' . $file . '.php not found in ' . $dir . '!', 81);
|
||||
}
|
||||
extract($this->_variables);
|
||||
include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template file path
|
||||
*
|
||||
* @access public
|
||||
* @param string $template
|
||||
* @return string
|
||||
*/
|
||||
public static function getTemplateFilePath(string $template): string
|
||||
{
|
||||
$file = self::isBootstrapTemplate($template) ? 'bootstrap' : $template;
|
||||
return PATH . 'tpl' . DIRECTORY_SEPARATOR . $file . '.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the template a variation of the bootstrap template
|
||||
*
|
||||
* @access public
|
||||
* @param string $template
|
||||
* @return bool
|
||||
*/
|
||||
public static function isBootstrapTemplate(string $template): bool
|
||||
{
|
||||
return substr($template, 0, 10) === 'bootstrap-';
|
||||
}
|
||||
|
||||
/**
|
||||
* echo script tag incl. SRI hash for given script file
|
||||
*
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ endif;
|
|||
<?php
|
||||
if ($QRCODE) :
|
||||
?>
|
||||
<?php $this->_scriptTag('js/kjua-0.9.0.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/kjua-0.10.0.js', 'async'); ?>
|
||||
<?php
|
||||
endif;
|
||||
if ($ZEROBINCOMPATIBILITY) :
|
||||
|
|
@ -56,7 +56,7 @@ if ($ZEROBINCOMPATIBILITY) :
|
|||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/zlib-1.3.1-1.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-4.0.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-5.0.1.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/rawinflate-0.3.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/bootstrap-3.4.1.js', 'defer'); ?>
|
||||
<?php
|
||||
|
|
@ -71,8 +71,8 @@ if ($MARKDOWN) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/purify-3.2.6.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/legacy.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/purify-3.3.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||
|
|
|
|||
|
|
@ -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.3.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) :
|
||||
|
|
@ -29,7 +29,7 @@ endif;
|
|||
<?php
|
||||
if ($QRCODE) :
|
||||
?>
|
||||
<?php $this->_scriptTag('js/kjua-0.9.0.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/kjua-0.10.0.js', 'async'); ?>
|
||||
<?php
|
||||
endif;
|
||||
if ($ZEROBINCOMPATIBILITY) :
|
||||
|
|
@ -39,9 +39,9 @@ if ($ZEROBINCOMPATIBILITY) :
|
|||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/zlib-1.3.1-1.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-4.0.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/base-x-5.0.1.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/rawinflate-0.3.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/bootstrap-5.3.3.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/bootstrap-5.3.8.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/dark-mode-switch.js', 'defer'); ?>
|
||||
<?php
|
||||
if ($SYNTAXHIGHLIGHTING) :
|
||||
|
|
@ -55,8 +55,8 @@ if ($MARKDOWN) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php $this->_scriptTag('js/purify-3.2.6.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/legacy.js', 'async'); ?>
|
||||
<?php $this->_scriptTag('js/purify-3.3.0.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
|
||||
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use Google\Cloud\Storage\Bucket;
|
|||
use Google\Cloud\Storage\Connection\ConnectionInterface;
|
||||
use Google\Cloud\Storage\StorageClient;
|
||||
use Google\Cloud\Storage\StorageObject;
|
||||
use PrivateBin\Configuration;
|
||||
use PrivateBin\Persistence\ServerSalt;
|
||||
use PrivateBin\TemplateSwitcher;
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
|
|
@ -26,6 +28,7 @@ if (!defined('CONF_SAMPLE')) {
|
|||
|
||||
require PATH . 'vendor/autoload.php';
|
||||
Helper::updateSubresourceIntegrity();
|
||||
TemplateSwitcher::setAvailableTemplates(Configuration::getDefaults()['main']['availabletemplates']);
|
||||
|
||||
/**
|
||||
* Class Helper provides unit tests pastes and comments of various formats
|
||||
|
|
|
|||
|
|
@ -143,19 +143,11 @@ class ViewTest extends TestCase
|
|||
$test->draw('123456789 does not exist!');
|
||||
}
|
||||
|
||||
public function testTemplateFilePath()
|
||||
public function testInvalidTemplate()
|
||||
{
|
||||
$template = 'bootstrap';
|
||||
$templatePath = PATH . 'tpl' . DIRECTORY_SEPARATOR . $template . '.php';
|
||||
$path = View::getTemplateFilePath($template);
|
||||
$this->assertEquals($templatePath, $path, 'Template file path');
|
||||
}
|
||||
|
||||
public function testIsBootstrapTemplate()
|
||||
{
|
||||
$bootstrapTemplate = 'bootstrap-dark';
|
||||
$nonBootstrapTemplate = 'page';
|
||||
$this->assertTrue(View::isBootstrapTemplate($bootstrapTemplate), 'Is bootstrap template');
|
||||
$this->assertFalse(View::isBootstrapTemplate($nonBootstrapTemplate), 'Is not bootstrap template');
|
||||
$test = new View;
|
||||
$this->expectException(Exception::class);
|
||||
$this->expectExceptionCode(81);
|
||||
$test->draw('../index');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
96
vendor/composer/ClassLoader.php
vendored
96
vendor/composer/ClassLoader.php
vendored
|
|
@ -45,35 +45,34 @@ class ClassLoader
|
|||
/** @var \Closure(string):void */
|
||||
private static $includeFile;
|
||||
|
||||
/** @var ?string */
|
||||
/** @var string|null */
|
||||
private $vendorDir;
|
||||
|
||||
// PSR-4
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, int>>
|
||||
* @var array<string, array<string, int>>
|
||||
*/
|
||||
private $prefixLengthsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<int, string>>
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
private $prefixDirsPsr4 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr4 = array();
|
||||
|
||||
// PSR-0
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, array<string, string[]>>
|
||||
* List of PSR-0 prefixes
|
||||
*
|
||||
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
private $prefixesPsr0 = array();
|
||||
/**
|
||||
* @var array[]
|
||||
* @psalm-var array<string, string>
|
||||
* @var list<string>
|
||||
*/
|
||||
private $fallbackDirsPsr0 = array();
|
||||
|
||||
|
|
@ -81,8 +80,7 @@ class ClassLoader
|
|||
private $useIncludePath = false;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
* @psalm-var array<string, string>
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private $classMap = array();
|
||||
|
||||
|
|
@ -90,21 +88,20 @@ class ClassLoader
|
|||
private $classMapAuthoritative = false;
|
||||
|
||||
/**
|
||||
* @var bool[]
|
||||
* @psalm-var array<string, bool>
|
||||
* @var array<string, bool>
|
||||
*/
|
||||
private $missingClasses = array();
|
||||
|
||||
/** @var ?string */
|
||||
/** @var string|null */
|
||||
private $apcuPrefix;
|
||||
|
||||
/**
|
||||
* @var self[]
|
||||
* @var array<string, self>
|
||||
*/
|
||||
private static $registeredLoaders = array();
|
||||
|
||||
/**
|
||||
* @param ?string $vendorDir
|
||||
* @param string|null $vendorDir
|
||||
*/
|
||||
public function __construct($vendorDir = null)
|
||||
{
|
||||
|
|
@ -113,7 +110,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixes()
|
||||
{
|
||||
|
|
@ -125,8 +122,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, array<int, string>>
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
public function getPrefixesPsr4()
|
||||
{
|
||||
|
|
@ -134,8 +130,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirs()
|
||||
{
|
||||
|
|
@ -143,8 +138,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
* @psalm-return array<string, string>
|
||||
* @return list<string>
|
||||
*/
|
||||
public function getFallbackDirsPsr4()
|
||||
{
|
||||
|
|
@ -152,8 +146,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @return string[] Array of classname => path
|
||||
* @psalm-return array<string, string>
|
||||
* @return array<string, string> Array of classname => path
|
||||
*/
|
||||
public function getClassMap()
|
||||
{
|
||||
|
|
@ -161,8 +154,7 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string[] $classMap Class to filename map
|
||||
* @psalm-param array<string, string> $classMap
|
||||
* @param array<string, string> $classMap Class to filename map
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
|
@ -179,24 +171,25 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix, either
|
||||
* appending or prepending to the ones previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 root directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
(array) $paths,
|
||||
$paths,
|
||||
$this->fallbackDirsPsr0
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr0 = array_merge(
|
||||
$this->fallbackDirsPsr0,
|
||||
(array) $paths
|
||||
$paths
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -205,19 +198,19 @@ class ClassLoader
|
|||
|
||||
$first = $prefix[0];
|
||||
if (!isset($this->prefixesPsr0[$first][$prefix])) {
|
||||
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
|
||||
$this->prefixesPsr0[$first][$prefix] = $paths;
|
||||
|
||||
return;
|
||||
}
|
||||
if ($prepend) {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$paths,
|
||||
$this->prefixesPsr0[$first][$prefix]
|
||||
);
|
||||
} else {
|
||||
$this->prefixesPsr0[$first][$prefix] = array_merge(
|
||||
$this->prefixesPsr0[$first][$prefix],
|
||||
(array) $paths
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -226,9 +219,9 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace, either
|
||||
* appending or prepending to the ones previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
* @param bool $prepend Whether to prepend the directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
|
|
@ -236,17 +229,18 @@ class ClassLoader
|
|||
*/
|
||||
public function addPsr4($prefix, $paths, $prepend = false)
|
||||
{
|
||||
$paths = (array) $paths;
|
||||
if (!$prefix) {
|
||||
// Register directories for the root namespace.
|
||||
if ($prepend) {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
(array) $paths,
|
||||
$paths,
|
||||
$this->fallbackDirsPsr4
|
||||
);
|
||||
} else {
|
||||
$this->fallbackDirsPsr4 = array_merge(
|
||||
$this->fallbackDirsPsr4,
|
||||
(array) $paths
|
||||
$paths
|
||||
);
|
||||
}
|
||||
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
|
||||
|
|
@ -256,18 +250,18 @@ class ClassLoader
|
|||
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
|
||||
}
|
||||
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
|
||||
$this->prefixDirsPsr4[$prefix] = (array) $paths;
|
||||
$this->prefixDirsPsr4[$prefix] = $paths;
|
||||
} elseif ($prepend) {
|
||||
// Prepend directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
(array) $paths,
|
||||
$paths,
|
||||
$this->prefixDirsPsr4[$prefix]
|
||||
);
|
||||
} else {
|
||||
// Append directories for an already registered namespace.
|
||||
$this->prefixDirsPsr4[$prefix] = array_merge(
|
||||
$this->prefixDirsPsr4[$prefix],
|
||||
(array) $paths
|
||||
$paths
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -276,8 +270,8 @@ class ClassLoader
|
|||
* Registers a set of PSR-0 directories for a given prefix,
|
||||
* replacing any others previously set for this prefix.
|
||||
*
|
||||
* @param string $prefix The prefix
|
||||
* @param string[]|string $paths The PSR-0 base directories
|
||||
* @param string $prefix The prefix
|
||||
* @param list<string>|string $paths The PSR-0 base directories
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
|
@ -294,8 +288,8 @@ class ClassLoader
|
|||
* Registers a set of PSR-4 directories for a given namespace,
|
||||
* replacing any others previously set for this namespace.
|
||||
*
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param string[]|string $paths The PSR-4 base directories
|
||||
* @param string $prefix The prefix/namespace, with trailing '\\'
|
||||
* @param list<string>|string $paths The PSR-4 base directories
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
|
|
@ -481,9 +475,9 @@ class ClassLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the currently registered loaders indexed by their corresponding vendor directories.
|
||||
* Returns the currently registered loaders keyed by their corresponding vendor directories.
|
||||
*
|
||||
* @return self[]
|
||||
* @return array<string, self>
|
||||
*/
|
||||
public static function getRegisteredLoaders()
|
||||
{
|
||||
|
|
|
|||
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
|
|
@ -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',
|
||||
|
|
|
|||
1
vendor/composer/autoload_static.php
vendored
1
vendor/composer/autoload_static.php
vendored
|
|
@ -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',
|
||||
|
|
|
|||
18
vendor/composer/installed.php
vendored
18
vendor/composer/installed.php
vendored
|
|
@ -1,9 +1,9 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'privatebin/privatebin',
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '7825471d70c39baf6042c52a453c8fe705d9ed75',
|
||||
'pretty_version' => 'dev-1.7-backport-2.0.3',
|
||||
'version' => 'dev-1.7-backport-2.0.3',
|
||||
'reference' => 'eb203e2d2505fd167de6f4c714562fad611b1ffa',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
|
@ -20,18 +20,18 @@
|
|||
'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(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'privatebin/privatebin' => array(
|
||||
'pretty_version' => 'dev-master',
|
||||
'version' => 'dev-master',
|
||||
'reference' => '7825471d70c39baf6042c52a453c8fe705d9ed75',
|
||||
'pretty_version' => 'dev-1.7-backport-2.0.3',
|
||||
'version' => 'dev-1.7-backport-2.0.3',
|
||||
'reference' => 'eb203e2d2505fd167de6f4c714562fad611b1ffa',
|
||||
'type' => 'project',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
36
vendor/mlocati/ip-lib/src/Address/IPv4.php
vendored
36
vendor/mlocati/ip-lib/src/Address/IPv4.php
vendored
|
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
38
vendor/mlocati/ip-lib/src/Address/IPv6.php
vendored
38
vendor/mlocati/ip-lib/src/Address/IPv6.php
vendored
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
17
vendor/mlocati/ip-lib/src/Range/Pattern.php
vendored
17
vendor/mlocati/ip-lib/src/Range/Pattern.php
vendored
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
10
vendor/mlocati/ip-lib/src/Range/Single.php
vendored
10
vendor/mlocati/ip-lib/src/Range/Single.php
vendored
|
|
@ -237,6 +237,16 @@ class Single extends AbstractRange
|
|||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @see \IPLib\Range\RangeInterface::getExactSize()
|
||||
*/
|
||||
public function getExactSize()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
|
|
|
|||
17
vendor/mlocati/ip-lib/src/Range/Subnet.php
vendored
17
vendor/mlocati/ip-lib/src/Range/Subnet.php
vendored
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
vendor/mlocati/ip-lib/src/Range/Type.php
vendored
22
vendor/mlocati/ip-lib/src/Range/Type.php
vendored
|
|
@ -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:
|
||||
|
|
|
|||
112
vendor/mlocati/ip-lib/src/Service/BinaryMath.php
vendored
112
vendor/mlocati/ip-lib/src/Service/BinaryMath.php
vendored
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
253
vendor/mlocati/ip-lib/src/Service/NumberInChunks.php
vendored
Normal file
253
vendor/mlocati/ip-lib/src/Service/NumberInChunks.php
vendored
Normal 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));
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ class RangesFromBoundaryCalculator
|
|||
*/
|
||||
public function __construct($numBits)
|
||||
{
|
||||
$this->math = new BinaryMath();
|
||||
$this->math = BinaryMath::getInstance();
|
||||
$this->setNumBits($numBits);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue