mirror of
https://framagit.org/hubzilla/core.git
synced 2026-06-21 00:52:33 -04:00
composer update
This commit is contained in:
170
composer.lock
generated
170
composer.lock
generated
@@ -658,20 +658,20 @@
|
||||
},
|
||||
{
|
||||
"name": "genkgo/php-asn1",
|
||||
"version": "v2.8.0",
|
||||
"version": "v2.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/genkgo/php-asn1.git",
|
||||
"reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb"
|
||||
"reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/genkgo/php-asn1/zipball/4de712c68bbf51c00551cb45f55642e30fed1fdb",
|
||||
"reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb",
|
||||
"url": "https://api.github.com/repos/genkgo/php-asn1/zipball/dc535345d0ecc69181c6a1e17e57a625bd01f891",
|
||||
"reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "~2.0",
|
||||
@@ -732,9 +732,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/genkgo/php-asn1/issues",
|
||||
"source": "https://github.com/genkgo/php-asn1/tree/v2.8.0"
|
||||
"source": "https://github.com/genkgo/php-asn1/tree/v2.9.0"
|
||||
},
|
||||
"time": "2025-02-12T20:20:53+00:00"
|
||||
"time": "2026-01-06T11:43:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
@@ -1014,20 +1014,20 @@
|
||||
},
|
||||
{
|
||||
"name": "league/uri",
|
||||
"version": "7.6.0",
|
||||
"version": "7.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri.git",
|
||||
"reference": "f625804987a0a9112d954f9209d91fec52182344"
|
||||
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/f625804987a0a9112d954f9209d91fec52182344",
|
||||
"reference": "f625804987a0a9112d954f9209d91fec52182344",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
|
||||
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/uri-interfaces": "^7.6",
|
||||
"league/uri-interfaces": "^7.7",
|
||||
"php": "^8.1",
|
||||
"psr/http-factory": "^1"
|
||||
},
|
||||
@@ -1100,7 +1100,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.6.0"
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1108,20 +1108,20 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-18T12:17:23+00:00"
|
||||
"time": "2025-12-07T16:02:06+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/uri-interfaces",
|
||||
"version": "7.6.0",
|
||||
"version": "7.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri-interfaces.git",
|
||||
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368"
|
||||
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/ccbfb51c0445298e7e0b7f4481b942f589665368",
|
||||
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
|
||||
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1184,7 +1184,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.6.0"
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1192,7 +1192,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-18T12:17:23+00:00"
|
||||
"time": "2025-12-07T16:03:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "lukasreschke/id3parser",
|
||||
@@ -1600,16 +1600,16 @@
|
||||
},
|
||||
{
|
||||
"name": "paragonie/sodium_compat",
|
||||
"version": "v2.4.0",
|
||||
"version": "v2.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/sodium_compat.git",
|
||||
"reference": "547e2dc4d45107440e76c17ab5a46e4252460158"
|
||||
"reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/547e2dc4d45107440e76c17ab5a46e4252460158",
|
||||
"reference": "547e2dc4d45107440e76c17ab5a46e4252460158",
|
||||
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/4714da6efdc782c06690bc72ce34fae7941c2d9f",
|
||||
"reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1690,9 +1690,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/paragonie/sodium_compat/issues",
|
||||
"source": "https://github.com/paragonie/sodium_compat/tree/v2.4.0"
|
||||
"source": "https://github.com/paragonie/sodium_compat/tree/v2.5.0"
|
||||
},
|
||||
"time": "2025-10-06T08:47:40+00:00"
|
||||
"time": "2025-12-30T16:12:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "patrickschur/language-detection",
|
||||
@@ -1795,16 +1795,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.47",
|
||||
"version": "3.0.48",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d"
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/9d6ca36a6c2dd434765b1071b2644a1c683b385d",
|
||||
"reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1885,7 +1885,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.47"
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.48"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1901,7 +1901,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-06T01:07:24+00:00"
|
||||
"time": "2025-12-15T11:51:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib2_compat",
|
||||
@@ -2279,20 +2279,20 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.9.1",
|
||||
"version": "4.9.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440"
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440",
|
||||
"reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
@@ -2351,9 +2351,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.9.1"
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.9.2"
|
||||
},
|
||||
"time": "2025-09-04T20:59:21+00:00"
|
||||
"time": "2025-12-14T04:43:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "root23/php-json-canonicalization",
|
||||
@@ -2665,16 +2665,16 @@
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
"version": "4.5.7",
|
||||
"version": "4.5.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/vobject.git",
|
||||
"reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c"
|
||||
"reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/ff22611a53782e90c97be0d0bc4a5f98a5c0a12c",
|
||||
"reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/d554eb24d64232922e1eab5896cc2f84b3b9ffb1",
|
||||
"reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2765,7 +2765,7 @@
|
||||
"issues": "https://github.com/sabre-io/vobject/issues",
|
||||
"source": "https://github.com/fruux/sabre-vobject"
|
||||
},
|
||||
"time": "2025-04-17T09:22:48+00:00"
|
||||
"time": "2026-01-12T10:45:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabre/xml",
|
||||
@@ -3131,38 +3131,26 @@
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/otphp",
|
||||
"version": "11.3.0",
|
||||
"version": "11.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Spomky-Labs/otphp.git",
|
||||
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33"
|
||||
"reference": "126c99b6cbbc18992cf3fba3b87931ba4e312482"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
|
||||
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/126c99b6cbbc18992cf3fba3b87931ba4e312482",
|
||||
"reference": "126c99b6cbbc18992cf3fba3b87931ba4e312482",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
|
||||
"php": ">=8.1",
|
||||
"psr/clock": "^1.0",
|
||||
"symfony/deprecation-contracts": "^3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ekino/phpstan-banned-code": "^1.0",
|
||||
"infection/infection": "^0.26|^0.27|^0.28|^0.29",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
|
||||
"qossmic/deptrac-shim": "^1.0",
|
||||
"rector/rector": "^1.0",
|
||||
"symfony/phpunit-bridge": "^6.1|^7.0",
|
||||
"symplify/easy-coding-standard": "^12.0"
|
||||
"symfony/error-handler": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -3197,7 +3185,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Spomky-Labs/otphp/issues",
|
||||
"source": "https://github.com/Spomky-Labs/otphp/tree/11.3.0"
|
||||
"source": "https://github.com/Spomky-Labs/otphp/tree/11.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3209,7 +3197,7 @@
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2024-06-12T11:22:32+00:00"
|
||||
"time": "2026-01-05T13:20:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "stephenhill/base58",
|
||||
@@ -4032,16 +4020,16 @@
|
||||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v5.6.2",
|
||||
"version": "v5.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "3a454ca033b9e06b63282ce19562e892747449bb"
|
||||
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/3a454ca033b9e06b63282ce19562e892747449bb",
|
||||
"reference": "3a454ca033b9e06b63282ce19562e892747449bb",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
|
||||
"reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4084,9 +4072,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.6.2"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
|
||||
},
|
||||
"time": "2025-10-21T19:32:17+00:00"
|
||||
"time": "2025-12-06T11:56:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pdepend/pdepend",
|
||||
@@ -4561,11 +4549,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.32",
|
||||
"version": "2.1.33",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e126cad1e30a99b137b8ed75a85a676450ebb227",
|
||||
"reference": "e126cad1e30a99b137b8ed75a85a676450ebb227",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f",
|
||||
"reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4610,7 +4598,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-11T15:18:17+00:00"
|
||||
"time": "2025-12-05T10:24:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -4935,16 +4923,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "10.5.59",
|
||||
"version": "10.5.60",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "c47fe00df06fb1f68399ef7386edb01c25132473"
|
||||
"reference": "f2e26f52f80ef77832e359205f216eeac00e320c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/c47fe00df06fb1f68399ef7386edb01c25132473",
|
||||
"reference": "c47fe00df06fb1f68399ef7386edb01c25132473",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f2e26f52f80ef77832e359205f216eeac00e320c",
|
||||
"reference": "f2e26f52f80ef77832e359205f216eeac00e320c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5016,7 +5004,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.59"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.60"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5040,7 +5028,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-12-01T07:37:23+00:00"
|
||||
"time": "2025-12-06T07:50:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
@@ -6129,16 +6117,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v7.4.0",
|
||||
"version": "v7.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/config.git",
|
||||
"reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41"
|
||||
"reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/f76c74e93bce2b9285f2dad7fbd06fa8182a7a41",
|
||||
"reference": "f76c74e93bce2b9285f2dad7fbd06fa8182a7a41",
|
||||
"url": "https://api.github.com/repos/symfony/config/zipball/800ce889e358a53a9678b3212b0c8cecd8c6aace",
|
||||
"reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6184,7 +6172,7 @@
|
||||
"description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/config/tree/v7.4.0"
|
||||
"source": "https://github.com/symfony/config/tree/v7.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6204,20 +6192,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-27T13:27:24+00:00"
|
||||
"time": "2025-12-23T14:24:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/dependency-injection",
|
||||
"version": "v7.4.0",
|
||||
"version": "v7.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/dependency-injection.git",
|
||||
"reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b"
|
||||
"reference": "54122901b6d772e94f1e71a75e0533bc16563499"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/3972ca7bbd649467b21a54870721b9e9f3652f9b",
|
||||
"reference": "3972ca7bbd649467b21a54870721b9e9f3652f9b",
|
||||
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54122901b6d772e94f1e71a75e0533bc16563499",
|
||||
"reference": "54122901b6d772e94f1e71a75e0533bc16563499",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6268,7 +6256,7 @@
|
||||
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v7.4.0"
|
||||
"source": "https://github.com/symfony/dependency-injection/tree/v7.4.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6288,7 +6276,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-11-27T13:27:24+00:00"
|
||||
"time": "2025-12-28T10:55:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
|
||||
12
vendor/composer/autoload_classmap.php
vendored
12
vendor/composer/autoload_classmap.php
vendored
@@ -473,6 +473,9 @@ return array(
|
||||
'League\\Uri\\Exceptions\\OffsetOutOfBounds' => $vendorDir . '/league/uri-interfaces/Exceptions/OffsetOutOfBounds.php',
|
||||
'League\\Uri\\Exceptions\\SyntaxError' => $vendorDir . '/league/uri-interfaces/Exceptions/SyntaxError.php',
|
||||
'League\\Uri\\FeatureDetection' => $vendorDir . '/league/uri-interfaces/FeatureDetection.php',
|
||||
'League\\Uri\\HostFormat' => $vendorDir . '/league/uri-interfaces/HostFormat.php',
|
||||
'League\\Uri\\HostRecord' => $vendorDir . '/league/uri-interfaces/HostRecord.php',
|
||||
'League\\Uri\\HostType' => $vendorDir . '/league/uri-interfaces/HostType.php',
|
||||
'League\\Uri\\Http' => $vendorDir . '/league/uri/Http.php',
|
||||
'League\\Uri\\HttpFactory' => $vendorDir . '/league/uri/HttpFactory.php',
|
||||
'League\\Uri\\IPv4\\BCMathCalculator' => $vendorDir . '/league/uri-interfaces/IPv4/BCMathCalculator.php',
|
||||
@@ -677,6 +680,12 @@ return array(
|
||||
'OAuth2\\TokenType\\Bearer' => $vendorDir . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php',
|
||||
'OAuth2\\TokenType\\Mac' => $vendorDir . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php',
|
||||
'OAuth2\\TokenType\\TokenTypeInterface' => $vendorDir . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php',
|
||||
'OTPHP\\Exception\\InvalidLabelException' => $vendorDir . '/spomky-labs/otphp/src/Exception/InvalidLabelException.php',
|
||||
'OTPHP\\Exception\\InvalidParameterException' => $vendorDir . '/spomky-labs/otphp/src/Exception/InvalidParameterException.php',
|
||||
'OTPHP\\Exception\\InvalidProvisioningUriException' => $vendorDir . '/spomky-labs/otphp/src/Exception/InvalidProvisioningUriException.php',
|
||||
'OTPHP\\Exception\\OTPExceptionInterface' => $vendorDir . '/spomky-labs/otphp/src/Exception/OTPExceptionInterface.php',
|
||||
'OTPHP\\Exception\\ParameterNotFoundException' => $vendorDir . '/spomky-labs/otphp/src/Exception/ParameterNotFoundException.php',
|
||||
'OTPHP\\Exception\\SecretDecodingException' => $vendorDir . '/spomky-labs/otphp/src/Exception/SecretDecodingException.php',
|
||||
'OTPHP\\Factory' => $vendorDir . '/spomky-labs/otphp/src/Factory.php',
|
||||
'OTPHP\\FactoryInterface' => $vendorDir . '/spomky-labs/otphp/src/FactoryInterface.php',
|
||||
'OTPHP\\HOTP' => $vendorDir . '/spomky-labs/otphp/src/HOTP.php',
|
||||
@@ -684,7 +693,6 @@ return array(
|
||||
'OTPHP\\InternalClock' => $vendorDir . '/spomky-labs/otphp/src/InternalClock.php',
|
||||
'OTPHP\\OTP' => $vendorDir . '/spomky-labs/otphp/src/OTP.php',
|
||||
'OTPHP\\OTPInterface' => $vendorDir . '/spomky-labs/otphp/src/OTPInterface.php',
|
||||
'OTPHP\\ParameterTrait' => $vendorDir . '/spomky-labs/otphp/src/ParameterTrait.php',
|
||||
'OTPHP\\TOTP' => $vendorDir . '/spomky-labs/otphp/src/TOTP.php',
|
||||
'OTPHP\\TOTPInterface' => $vendorDir . '/spomky-labs/otphp/src/TOTPInterface.php',
|
||||
'OTPHP\\Url' => $vendorDir . '/spomky-labs/otphp/src/Url.php',
|
||||
@@ -2446,6 +2454,7 @@ return array(
|
||||
'Zotlabs\\Update\\_1262' => $baseDir . '/Zotlabs/Update/_1262.php',
|
||||
'Zotlabs\\Update\\_1263' => $baseDir . '/Zotlabs/Update/_1263.php',
|
||||
'Zotlabs\\Update\\_1264' => $baseDir . '/Zotlabs/Update/_1264.php',
|
||||
'Zotlabs\\Update\\_1265' => $baseDir . '/Zotlabs/Update/_1265.php',
|
||||
'Zotlabs\\Web\\Controller' => $baseDir . '/Zotlabs/Web/Controller.php',
|
||||
'Zotlabs\\Web\\HTTPHeaders' => $baseDir . '/Zotlabs/Web/HTTPHeaders.php',
|
||||
'Zotlabs\\Web\\HTTPSig' => $baseDir . '/Zotlabs/Web/HTTPSig.php',
|
||||
@@ -2912,6 +2921,7 @@ return array(
|
||||
'phpseclib3\\Math\\Common\\FiniteField\\Integer' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField/Integer.php',
|
||||
'phpseclib3\\Math\\PrimeField' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/PrimeField.php',
|
||||
'phpseclib3\\Math\\PrimeField\\Integer' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php',
|
||||
'phpseclib3\\Net\\SCP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
|
||||
'phpseclib3\\Net\\SFTP' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
|
||||
'phpseclib3\\Net\\SFTP\\Stream' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
|
||||
'phpseclib3\\Net\\SSH2' => $vendorDir . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
|
||||
|
||||
12
vendor/composer/autoload_static.php
vendored
12
vendor/composer/autoload_static.php
vendored
@@ -812,6 +812,9 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
|
||||
'League\\Uri\\Exceptions\\OffsetOutOfBounds' => __DIR__ . '/..' . '/league/uri-interfaces/Exceptions/OffsetOutOfBounds.php',
|
||||
'League\\Uri\\Exceptions\\SyntaxError' => __DIR__ . '/..' . '/league/uri-interfaces/Exceptions/SyntaxError.php',
|
||||
'League\\Uri\\FeatureDetection' => __DIR__ . '/..' . '/league/uri-interfaces/FeatureDetection.php',
|
||||
'League\\Uri\\HostFormat' => __DIR__ . '/..' . '/league/uri-interfaces/HostFormat.php',
|
||||
'League\\Uri\\HostRecord' => __DIR__ . '/..' . '/league/uri-interfaces/HostRecord.php',
|
||||
'League\\Uri\\HostType' => __DIR__ . '/..' . '/league/uri-interfaces/HostType.php',
|
||||
'League\\Uri\\Http' => __DIR__ . '/..' . '/league/uri/Http.php',
|
||||
'League\\Uri\\HttpFactory' => __DIR__ . '/..' . '/league/uri/HttpFactory.php',
|
||||
'League\\Uri\\IPv4\\BCMathCalculator' => __DIR__ . '/..' . '/league/uri-interfaces/IPv4/BCMathCalculator.php',
|
||||
@@ -1016,6 +1019,12 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
|
||||
'OAuth2\\TokenType\\Bearer' => __DIR__ . '/..' . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Bearer.php',
|
||||
'OAuth2\\TokenType\\Mac' => __DIR__ . '/..' . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/Mac.php',
|
||||
'OAuth2\\TokenType\\TokenTypeInterface' => __DIR__ . '/..' . '/bshaffer/oauth2-server-php/src/OAuth2/TokenType/TokenTypeInterface.php',
|
||||
'OTPHP\\Exception\\InvalidLabelException' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/InvalidLabelException.php',
|
||||
'OTPHP\\Exception\\InvalidParameterException' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/InvalidParameterException.php',
|
||||
'OTPHP\\Exception\\InvalidProvisioningUriException' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/InvalidProvisioningUriException.php',
|
||||
'OTPHP\\Exception\\OTPExceptionInterface' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/OTPExceptionInterface.php',
|
||||
'OTPHP\\Exception\\ParameterNotFoundException' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/ParameterNotFoundException.php',
|
||||
'OTPHP\\Exception\\SecretDecodingException' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Exception/SecretDecodingException.php',
|
||||
'OTPHP\\Factory' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Factory.php',
|
||||
'OTPHP\\FactoryInterface' => __DIR__ . '/..' . '/spomky-labs/otphp/src/FactoryInterface.php',
|
||||
'OTPHP\\HOTP' => __DIR__ . '/..' . '/spomky-labs/otphp/src/HOTP.php',
|
||||
@@ -1023,7 +1032,6 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
|
||||
'OTPHP\\InternalClock' => __DIR__ . '/..' . '/spomky-labs/otphp/src/InternalClock.php',
|
||||
'OTPHP\\OTP' => __DIR__ . '/..' . '/spomky-labs/otphp/src/OTP.php',
|
||||
'OTPHP\\OTPInterface' => __DIR__ . '/..' . '/spomky-labs/otphp/src/OTPInterface.php',
|
||||
'OTPHP\\ParameterTrait' => __DIR__ . '/..' . '/spomky-labs/otphp/src/ParameterTrait.php',
|
||||
'OTPHP\\TOTP' => __DIR__ . '/..' . '/spomky-labs/otphp/src/TOTP.php',
|
||||
'OTPHP\\TOTPInterface' => __DIR__ . '/..' . '/spomky-labs/otphp/src/TOTPInterface.php',
|
||||
'OTPHP\\Url' => __DIR__ . '/..' . '/spomky-labs/otphp/src/Url.php',
|
||||
@@ -2785,6 +2793,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
|
||||
'Zotlabs\\Update\\_1262' => __DIR__ . '/../..' . '/Zotlabs/Update/_1262.php',
|
||||
'Zotlabs\\Update\\_1263' => __DIR__ . '/../..' . '/Zotlabs/Update/_1263.php',
|
||||
'Zotlabs\\Update\\_1264' => __DIR__ . '/../..' . '/Zotlabs/Update/_1264.php',
|
||||
'Zotlabs\\Update\\_1265' => __DIR__ . '/../..' . '/Zotlabs/Update/_1265.php',
|
||||
'Zotlabs\\Web\\Controller' => __DIR__ . '/../..' . '/Zotlabs/Web/Controller.php',
|
||||
'Zotlabs\\Web\\HTTPHeaders' => __DIR__ . '/../..' . '/Zotlabs/Web/HTTPHeaders.php',
|
||||
'Zotlabs\\Web\\HTTPSig' => __DIR__ . '/../..' . '/Zotlabs/Web/HTTPSig.php',
|
||||
@@ -3251,6 +3260,7 @@ class ComposerStaticInit7b34d7e50a62201ec5d5e526a5b8b35d
|
||||
'phpseclib3\\Math\\Common\\FiniteField\\Integer' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField/Integer.php',
|
||||
'phpseclib3\\Math\\PrimeField' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/PrimeField.php',
|
||||
'phpseclib3\\Math\\PrimeField\\Integer' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php',
|
||||
'phpseclib3\\Net\\SCP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SCP.php',
|
||||
'phpseclib3\\Net\\SFTP' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP.php',
|
||||
'phpseclib3\\Net\\SFTP\\Stream' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php',
|
||||
'phpseclib3\\Net\\SSH2' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/Net/SSH2.php',
|
||||
|
||||
130
vendor/composer/installed.json
vendored
130
vendor/composer/installed.json
vendored
@@ -678,21 +678,21 @@
|
||||
},
|
||||
{
|
||||
"name": "genkgo/php-asn1",
|
||||
"version": "v2.8.0",
|
||||
"version_normalized": "2.8.0.0",
|
||||
"version": "v2.9.0",
|
||||
"version_normalized": "2.9.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/genkgo/php-asn1.git",
|
||||
"reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb"
|
||||
"reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/genkgo/php-asn1/zipball/4de712c68bbf51c00551cb45f55642e30fed1fdb",
|
||||
"reference": "4de712c68bbf51c00551cb45f55642e30fed1fdb",
|
||||
"url": "https://api.github.com/repos/genkgo/php-asn1/zipball/dc535345d0ecc69181c6a1e17e57a625bd01f891",
|
||||
"reference": "dc535345d0ecc69181c6a1e17e57a625bd01f891",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-coveralls/php-coveralls": "~2.0",
|
||||
@@ -704,7 +704,7 @@
|
||||
"ext-gmp": "GMP is the preferred extension for big integer calculations",
|
||||
"phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available"
|
||||
},
|
||||
"time": "2025-02-12T20:20:53+00:00",
|
||||
"time": "2026-01-06T11:43:05+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -755,7 +755,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/genkgo/php-asn1/issues",
|
||||
"source": "https://github.com/genkgo/php-asn1/tree/v2.8.0"
|
||||
"source": "https://github.com/genkgo/php-asn1/tree/v2.9.0"
|
||||
},
|
||||
"install-path": "../genkgo/php-asn1"
|
||||
},
|
||||
@@ -1046,21 +1046,21 @@
|
||||
},
|
||||
{
|
||||
"name": "league/uri",
|
||||
"version": "7.6.0",
|
||||
"version_normalized": "7.6.0.0",
|
||||
"version": "7.7.0",
|
||||
"version_normalized": "7.7.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri.git",
|
||||
"reference": "f625804987a0a9112d954f9209d91fec52182344"
|
||||
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/f625804987a0a9112d954f9209d91fec52182344",
|
||||
"reference": "f625804987a0a9112d954f9209d91fec52182344",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri/zipball/8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
|
||||
"reference": "8d587cddee53490f9b82bf203d3a9aa7ea4f9807",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"league/uri-interfaces": "^7.6",
|
||||
"league/uri-interfaces": "^7.7",
|
||||
"php": "^8.1",
|
||||
"psr/http-factory": "^1"
|
||||
},
|
||||
@@ -1081,7 +1081,7 @@
|
||||
"rowbot/url": "to handle WHATWG URL",
|
||||
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
|
||||
},
|
||||
"time": "2025-11-18T12:17:23+00:00",
|
||||
"time": "2025-12-07T16:02:06+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -1135,7 +1135,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.6.0"
|
||||
"source": "https://github.com/thephpleague/uri/tree/7.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1147,17 +1147,17 @@
|
||||
},
|
||||
{
|
||||
"name": "league/uri-interfaces",
|
||||
"version": "7.6.0",
|
||||
"version_normalized": "7.6.0.0",
|
||||
"version": "7.7.0",
|
||||
"version_normalized": "7.7.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/uri-interfaces.git",
|
||||
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368"
|
||||
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/ccbfb51c0445298e7e0b7f4481b942f589665368",
|
||||
"reference": "ccbfb51c0445298e7e0b7f4481b942f589665368",
|
||||
"url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
|
||||
"reference": "62ccc1a0435e1c54e10ee6022df28d6c04c2946c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1173,7 +1173,7 @@
|
||||
"rowbot/url": "to handle WHATWG URL",
|
||||
"symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present"
|
||||
},
|
||||
"time": "2025-11-18T12:17:23+00:00",
|
||||
"time": "2025-12-07T16:03:21+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -1222,7 +1222,7 @@
|
||||
"docs": "https://uri.thephpleague.com",
|
||||
"forum": "https://thephpleague.slack.com",
|
||||
"issues": "https://github.com/thephpleague/uri-src/issues",
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.6.0"
|
||||
"source": "https://github.com/thephpleague/uri-interfaces/tree/7.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -1655,17 +1655,17 @@
|
||||
},
|
||||
{
|
||||
"name": "paragonie/sodium_compat",
|
||||
"version": "v2.4.0",
|
||||
"version_normalized": "2.4.0.0",
|
||||
"version": "v2.5.0",
|
||||
"version_normalized": "2.5.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/sodium_compat.git",
|
||||
"reference": "547e2dc4d45107440e76c17ab5a46e4252460158"
|
||||
"reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/547e2dc4d45107440e76c17ab5a46e4252460158",
|
||||
"reference": "547e2dc4d45107440e76c17ab5a46e4252460158",
|
||||
"url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/4714da6efdc782c06690bc72ce34fae7941c2d9f",
|
||||
"reference": "4714da6efdc782c06690bc72ce34fae7941c2d9f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1681,7 +1681,7 @@
|
||||
"suggest": {
|
||||
"ext-sodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security."
|
||||
},
|
||||
"time": "2025-10-06T08:47:40+00:00",
|
||||
"time": "2025-12-30T16:12:18+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
@@ -1748,7 +1748,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/paragonie/sodium_compat/issues",
|
||||
"source": "https://github.com/paragonie/sodium_compat/tree/v2.4.0"
|
||||
"source": "https://github.com/paragonie/sodium_compat/tree/v2.5.0"
|
||||
},
|
||||
"install-path": "../paragonie/sodium_compat"
|
||||
},
|
||||
@@ -1859,17 +1859,17 @@
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
"version": "3.0.47",
|
||||
"version_normalized": "3.0.47.0",
|
||||
"version": "3.0.48",
|
||||
"version_normalized": "3.0.48.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpseclib/phpseclib.git",
|
||||
"reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d"
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/9d6ca36a6c2dd434765b1071b2644a1c683b385d",
|
||||
"reference": "9d6ca36a6c2dd434765b1071b2644a1c683b385d",
|
||||
"url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"reference": "64065a5679c50acb886e82c07aa139b0f757bb89",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1887,7 +1887,7 @@
|
||||
"ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.",
|
||||
"ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations."
|
||||
},
|
||||
"time": "2025-10-06T01:07:24+00:00",
|
||||
"time": "2025-12-15T11:51:42+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
@@ -1952,7 +1952,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpseclib/phpseclib/issues",
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.47"
|
||||
"source": "https://github.com/phpseclib/phpseclib/tree/3.0.48"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2367,21 +2367,21 @@
|
||||
},
|
||||
{
|
||||
"name": "ramsey/uuid",
|
||||
"version": "4.9.1",
|
||||
"version_normalized": "4.9.1.0",
|
||||
"version": "4.9.2",
|
||||
"version_normalized": "4.9.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ramsey/uuid.git",
|
||||
"reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440"
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440",
|
||||
"reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440",
|
||||
"url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"reference": "8429c78ca35a09f27565311b98101e2826affde0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"php": "^8.0",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
@@ -2414,7 +2414,7 @@
|
||||
"paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter",
|
||||
"ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type."
|
||||
},
|
||||
"time": "2025-09-04T20:59:21+00:00",
|
||||
"time": "2025-12-14T04:43:48+00:00",
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"captainhook": {
|
||||
@@ -2442,7 +2442,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ramsey/uuid/issues",
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.9.1"
|
||||
"source": "https://github.com/ramsey/uuid/tree/4.9.2"
|
||||
},
|
||||
"install-path": "../ramsey/uuid"
|
||||
},
|
||||
@@ -2771,17 +2771,17 @@
|
||||
},
|
||||
{
|
||||
"name": "sabre/vobject",
|
||||
"version": "4.5.7",
|
||||
"version_normalized": "4.5.7.0",
|
||||
"version": "4.5.8",
|
||||
"version_normalized": "4.5.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sabre-io/vobject.git",
|
||||
"reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c"
|
||||
"reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/ff22611a53782e90c97be0d0bc4a5f98a5c0a12c",
|
||||
"reference": "ff22611a53782e90c97be0d0bc4a5f98a5c0a12c",
|
||||
"url": "https://api.github.com/repos/sabre-io/vobject/zipball/d554eb24d64232922e1eab5896cc2f84b3b9ffb1",
|
||||
"reference": "d554eb24d64232922e1eab5896cc2f84b3b9ffb1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2798,7 +2798,7 @@
|
||||
"suggest": {
|
||||
"hoa/bench": "If you would like to run the benchmark scripts"
|
||||
},
|
||||
"time": "2025-04-17T09:22:48+00:00",
|
||||
"time": "2026-01-12T10:45:19+00:00",
|
||||
"bin": [
|
||||
"bin/vobject",
|
||||
"bin/generate_vcards"
|
||||
@@ -3255,41 +3255,29 @@
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/otphp",
|
||||
"version": "11.3.0",
|
||||
"version_normalized": "11.3.0.0",
|
||||
"version": "11.4.1",
|
||||
"version_normalized": "11.4.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Spomky-Labs/otphp.git",
|
||||
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33"
|
||||
"reference": "126c99b6cbbc18992cf3fba3b87931ba4e312482"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
|
||||
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/126c99b6cbbc18992cf3fba3b87931ba4e312482",
|
||||
"reference": "126c99b6cbbc18992cf3fba3b87931ba4e312482",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
|
||||
"php": ">=8.1",
|
||||
"psr/clock": "^1.0",
|
||||
"symfony/deprecation-contracts": "^3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ekino/phpstan-banned-code": "^1.0",
|
||||
"infection/infection": "^0.26|^0.27|^0.28|^0.29",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
|
||||
"qossmic/deptrac-shim": "^1.0",
|
||||
"rector/rector": "^1.0",
|
||||
"symfony/phpunit-bridge": "^6.1|^7.0",
|
||||
"symplify/easy-coding-standard": "^12.0"
|
||||
"symfony/error-handler": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"time": "2024-06-12T11:22:32+00:00",
|
||||
"time": "2026-01-05T13:20:36+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
@@ -3324,7 +3312,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Spomky-Labs/otphp/issues",
|
||||
"source": "https://github.com/Spomky-Labs/otphp/tree/11.3.0"
|
||||
"source": "https://github.com/Spomky-Labs/otphp/tree/11.4.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
||||
54
vendor/composer/installed.php
vendored
54
vendor/composer/installed.php
vendored
@@ -3,7 +3,7 @@
|
||||
'name' => 'zotlabs/hubzilla',
|
||||
'pretty_version' => 'dev-10.6RC',
|
||||
'version' => 'dev-10.6RC',
|
||||
'reference' => '5432819788d7e84b919966d6e8e556919f34b892',
|
||||
'reference' => '38f040f9b528378aa796fc0d72e971cb30bc9bd4',
|
||||
'type' => 'application',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -101,9 +101,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'genkgo/php-asn1' => array(
|
||||
'pretty_version' => 'v2.8.0',
|
||||
'version' => '2.8.0.0',
|
||||
'reference' => '4de712c68bbf51c00551cb45f55642e30fed1fdb',
|
||||
'pretty_version' => 'v2.9.0',
|
||||
'version' => '2.9.0.0',
|
||||
'reference' => 'dc535345d0ecc69181c6a1e17e57a625bd01f891',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../genkgo/php-asn1',
|
||||
'aliases' => array(),
|
||||
@@ -137,18 +137,18 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'league/uri' => array(
|
||||
'pretty_version' => '7.6.0',
|
||||
'version' => '7.6.0.0',
|
||||
'reference' => 'f625804987a0a9112d954f9209d91fec52182344',
|
||||
'pretty_version' => '7.7.0',
|
||||
'version' => '7.7.0.0',
|
||||
'reference' => '8d587cddee53490f9b82bf203d3a9aa7ea4f9807',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../league/uri',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'league/uri-interfaces' => array(
|
||||
'pretty_version' => '7.6.0',
|
||||
'version' => '7.6.0.0',
|
||||
'reference' => 'ccbfb51c0445298e7e0b7f4481b942f589665368',
|
||||
'pretty_version' => '7.7.0',
|
||||
'version' => '7.7.0.0',
|
||||
'reference' => '62ccc1a0435e1c54e10ee6022df28d6c04c2946c',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../league/uri-interfaces',
|
||||
'aliases' => array(),
|
||||
@@ -218,9 +218,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'paragonie/sodium_compat' => array(
|
||||
'pretty_version' => 'v2.4.0',
|
||||
'version' => '2.4.0.0',
|
||||
'reference' => '547e2dc4d45107440e76c17ab5a46e4252460158',
|
||||
'pretty_version' => 'v2.5.0',
|
||||
'version' => '2.5.0.0',
|
||||
'reference' => '4714da6efdc782c06690bc72ce34fae7941c2d9f',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../paragonie/sodium_compat',
|
||||
'aliases' => array(),
|
||||
@@ -245,9 +245,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'phpseclib/phpseclib' => array(
|
||||
'pretty_version' => '3.0.47',
|
||||
'version' => '3.0.47.0',
|
||||
'reference' => '9d6ca36a6c2dd434765b1071b2644a1c683b385d',
|
||||
'pretty_version' => '3.0.48',
|
||||
'version' => '3.0.48.0',
|
||||
'reference' => '64065a5679c50acb886e82c07aa139b0f757bb89',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../phpseclib/phpseclib',
|
||||
'aliases' => array(),
|
||||
@@ -332,9 +332,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'ramsey/uuid' => array(
|
||||
'pretty_version' => '4.9.1',
|
||||
'version' => '4.9.1.0',
|
||||
'reference' => '81f941f6f729b1e3ceea61d9d014f8b6c6800440',
|
||||
'pretty_version' => '4.9.2',
|
||||
'version' => '4.9.2.0',
|
||||
'reference' => '8429c78ca35a09f27565311b98101e2826affde0',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../ramsey/uuid',
|
||||
'aliases' => array(),
|
||||
@@ -343,7 +343,7 @@
|
||||
'rhumsaa/uuid' => array(
|
||||
'dev_requirement' => false,
|
||||
'replaced' => array(
|
||||
0 => '4.9.1',
|
||||
0 => '4.9.2',
|
||||
),
|
||||
),
|
||||
'root23/php-json-canonicalization' => array(
|
||||
@@ -392,9 +392,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'sabre/vobject' => array(
|
||||
'pretty_version' => '4.5.7',
|
||||
'version' => '4.5.7.0',
|
||||
'reference' => 'ff22611a53782e90c97be0d0bc4a5f98a5c0a12c',
|
||||
'pretty_version' => '4.5.8',
|
||||
'version' => '4.5.8.0',
|
||||
'reference' => 'd554eb24d64232922e1eab5896cc2f84b3b9ffb1',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../sabre/vobject',
|
||||
'aliases' => array(),
|
||||
@@ -446,9 +446,9 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'spomky-labs/otphp' => array(
|
||||
'pretty_version' => '11.3.0',
|
||||
'version' => '11.3.0.0',
|
||||
'reference' => '2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33',
|
||||
'pretty_version' => '11.4.1',
|
||||
'version' => '11.4.1.0',
|
||||
'reference' => '126c99b6cbbc18992cf3fba3b87931ba4e312482',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../spomky-labs/otphp',
|
||||
'aliases' => array(),
|
||||
@@ -544,7 +544,7 @@
|
||||
'zotlabs/hubzilla' => array(
|
||||
'pretty_version' => 'dev-10.6RC',
|
||||
'version' => 'dev-10.6RC',
|
||||
'reference' => '5432819788d7e84b919966d6e8e556919f34b892',
|
||||
'reference' => '38f040f9b528378aa796fc0d72e971cb30bc9bd4',
|
||||
'type' => 'application',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
||||
2
vendor/genkgo/php-asn1/composer.json
vendored
2
vendor/genkgo/php-asn1/composer.json
vendored
@@ -24,7 +24,7 @@
|
||||
"keywords": [ "x690", "x.690", "x.509", "x509", "asn1", "asn.1", "ber", "der", "binary", "encoding", "decoding" ],
|
||||
|
||||
"require": {
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0",
|
||||
|
||||
@@ -71,7 +71,7 @@ interface SegmentedPathInterface extends Countable, IteratorAggregate, PathInter
|
||||
/**
|
||||
* Appends a segment to the path.
|
||||
*/
|
||||
public function append(Stringable|string $segment): self;
|
||||
public function append(Stringable|string $path): self;
|
||||
|
||||
/**
|
||||
* Extracts a slice of $length elements starting at position $offset from the host.
|
||||
@@ -86,7 +86,7 @@ interface SegmentedPathInterface extends Countable, IteratorAggregate, PathInter
|
||||
/**
|
||||
* Prepends a segment to the path.
|
||||
*/
|
||||
public function prepend(Stringable|string $segment): self;
|
||||
public function prepend(Stringable|string $path): self;
|
||||
|
||||
/**
|
||||
* Returns an instance with the modified segment.
|
||||
|
||||
20
vendor/league/uri-interfaces/HostFormat.php
vendored
Normal file
20
vendor/league/uri-interfaces/HostFormat.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
enum HostFormat
|
||||
{
|
||||
case Ascii;
|
||||
case Unicode;
|
||||
}
|
||||
441
vendor/league/uri-interfaces/HostRecord.php
vendored
Normal file
441
vendor/league/uri-interfaces/HostRecord.php
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use Exception;
|
||||
use JsonSerializable;
|
||||
use League\Uri\Contracts\UriComponentInterface;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Idna\Converter as IdnConverter;
|
||||
use Stringable;
|
||||
use Throwable;
|
||||
|
||||
use function array_key_first;
|
||||
use function count;
|
||||
use function explode;
|
||||
use function filter_var;
|
||||
use function get_object_vars;
|
||||
use function in_array;
|
||||
use function inet_pton;
|
||||
use function is_object;
|
||||
use function preg_match;
|
||||
use function rawurldecode;
|
||||
use function strpos;
|
||||
use function strtolower;
|
||||
use function substr;
|
||||
|
||||
use const FILTER_FLAG_IPV4;
|
||||
use const FILTER_FLAG_IPV6;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
/**
|
||||
* @phpstan-type HostRecordSerializedShape array{0: array{host: ?string}, 1: array{}}
|
||||
*/
|
||||
final class HostRecord implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* Maximum number of host cached.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private const MAXIMUM_HOST_CACHED = 100;
|
||||
|
||||
private const REGEXP_NON_ASCII_PATTERN = '/[^\x20-\x7f]/';
|
||||
|
||||
/**
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* invalid characters in host regular expression
|
||||
*/
|
||||
private const REGEXP_INVALID_HOST_CHARS = '/
|
||||
[:\/?#\[\]@ ] # gen-delims characters as well as the space character
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* General registered name regular expression.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @see https://regex101.com/r/fptU8V/1
|
||||
*/
|
||||
private const REGEXP_REGISTERED_NAME = '/
|
||||
(?(DEFINE)
|
||||
(?<unreserved>[a-z0-9_~\-]) # . is missing as it is used to separate labels
|
||||
(?<sub_delims>[!$&\'()*+,;=])
|
||||
(?<encoded>%[A-F0-9]{2})
|
||||
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
|
||||
)
|
||||
^(?:(?®_name)\.)*(?®_name)\.?$
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* Domain name regular expression.
|
||||
*
|
||||
* Everything but the domain name length is validated
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc1034#section-3.5
|
||||
* @see https://tools.ietf.org/html/rfc1123#section-2.1
|
||||
* @see https://regex101.com/r/71j6rt/1
|
||||
*/
|
||||
private const REGEXP_DOMAIN_NAME = '/
|
||||
(?(DEFINE)
|
||||
(?<let_dig> [a-z0-9]) # alpha digit
|
||||
(?<let_dig_hyp> [a-z0-9-]) # alpha digit and hyphen
|
||||
(?<ldh_str> (?&let_dig_hyp){0,61}(?&let_dig)) # domain label end
|
||||
(?<label> (?&let_dig)((?&ldh_str))?) # domain label
|
||||
(?<domain> (?&label)(\.(?&label)){0,126}\.?) # domain name
|
||||
)
|
||||
^(?&domain)$
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* @see https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* IPvFuture regular expression
|
||||
*/
|
||||
private const REGEXP_IP_FUTURE = '/^
|
||||
v(?<version>[A-F\d])+\.
|
||||
(?:
|
||||
(?<unreserved>[a-z\d_~\-\.])|
|
||||
(?<sub_delims>[!$&\'()*+,;=:]) # also include the : character
|
||||
)+
|
||||
$/ix';
|
||||
private const REGEXP_GEN_DELIMS = '/[:\/?#\[\]@ ]/';
|
||||
private const ADDRESS_BLOCK = "\xfe\x80";
|
||||
|
||||
private ?bool $isDomainName = null;
|
||||
private ?bool $hasZoneIdentifier = null;
|
||||
private bool $asciiIsLoaded = false;
|
||||
private ?string $hostAsAscii = null;
|
||||
private bool $unicodeIsLoaded = false;
|
||||
private ?string $hostAsUnicode = null;
|
||||
private bool $isIpVersionLoaded = false;
|
||||
private ?string $ipVersion = null;
|
||||
private bool $isIpValueLoaded = false;
|
||||
private ?string $ipValue = null;
|
||||
|
||||
private function __construct(
|
||||
public readonly ?string $value,
|
||||
public readonly HostType $type,
|
||||
public readonly HostFormat $format
|
||||
) {
|
||||
}
|
||||
|
||||
public function hasZoneIdentifier(): bool
|
||||
{
|
||||
return $this->hasZoneIdentifier ??= HostType::Ipv6 === $this->type && str_contains((string) $this->value, '%');
|
||||
}
|
||||
|
||||
public function toAscii(): ?string
|
||||
{
|
||||
if (!$this->asciiIsLoaded) {
|
||||
$this->asciiIsLoaded = true;
|
||||
$this->hostAsAscii = (function (): ?string {
|
||||
if (HostType::RegisteredName !== $this->type || null === $this->value) {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
$formattedHost = rawurldecode($this->value);
|
||||
if ($formattedHost === $this->value) {
|
||||
return $this->isDomainType() ? IdnConverter::toAscii($this->value)->domain() : strtolower($formattedHost);
|
||||
}
|
||||
|
||||
return Encoder::normalizeHost($this->value);
|
||||
})();
|
||||
}
|
||||
|
||||
return $this->hostAsAscii;
|
||||
}
|
||||
|
||||
public function toUnicode(): ?string
|
||||
{
|
||||
if (!$this->unicodeIsLoaded) {
|
||||
$this->unicodeIsLoaded = true;
|
||||
$this->hostAsUnicode = $this->isDomainType() && null !== $this->value ? IdnConverter::toUnicode($this->value)->domain() : $this->value;
|
||||
}
|
||||
|
||||
return $this->hostAsUnicode;
|
||||
}
|
||||
|
||||
public function isDomainType(): bool
|
||||
{
|
||||
return $this->isDomainName ??= match (true) {
|
||||
HostType::RegisteredName !== $this->type, '' === $this->value => false,
|
||||
null === $this->value => true,
|
||||
default => is_object($result = IdnConverter::toAscii($this->value))
|
||||
&& !$result->hasErrors()
|
||||
&& self::isValidDomain($result->domain()),
|
||||
};
|
||||
}
|
||||
|
||||
public function ipVersion(): ?string
|
||||
{
|
||||
if (!$this->isIpVersionLoaded) {
|
||||
$this->isIpVersionLoaded = true;
|
||||
$this->ipVersion = match (true) {
|
||||
HostType::Ipv4 === $this->type => '4',
|
||||
HostType::Ipv6 === $this->type => '6',
|
||||
1 === preg_match(self::REGEXP_IP_FUTURE, substr((string) $this->value, 1, -1), $matches) => $matches['version'],
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
return $this->ipVersion;
|
||||
}
|
||||
|
||||
public function ipValue(): ?string
|
||||
{
|
||||
if (!$this->isIpValueLoaded) {
|
||||
$this->isIpValueLoaded = true;
|
||||
$this->ipValue = (function (): ?string {
|
||||
if (HostType::RegisteredName === $this->type) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (HostType::Ipv4 === $this->type) {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
$ip = substr((string) $this->value, 1, -1);
|
||||
if (HostType::Ipv6 !== $this->type) {
|
||||
return substr($ip, (int) strpos($ip, '.') + 1);
|
||||
}
|
||||
|
||||
$pos = strpos($ip, '%');
|
||||
if (false === $pos) {
|
||||
return $ip;
|
||||
}
|
||||
|
||||
return substr($ip, 0, $pos).'%'.rawurldecode(substr($ip, $pos + 3));
|
||||
})();
|
||||
}
|
||||
|
||||
return $this->ipValue;
|
||||
}
|
||||
|
||||
public static function isValid(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
HostRecord::from($host);
|
||||
|
||||
return true;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isIpv4(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
return HostType::Ipv4 === HostRecord::from($host)->type;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isIpv6(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
return HostType::Ipv6 === HostRecord::from($host)->type;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isIpvFuture(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
return HostType::IpvFuture === HostRecord::from($host)->type;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isIp(Stringable|string|null $host): bool
|
||||
{
|
||||
return !self::isRegisteredName($host);
|
||||
}
|
||||
|
||||
public static function isRegisteredName(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
return HostType::RegisteredName === HostRecord::from($host)->type;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function isDomain(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
return HostRecord::from($host)->isDomainType();
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SyntaxError
|
||||
*/
|
||||
public static function from(Stringable|string|null $host): self
|
||||
{
|
||||
if ($host instanceof UriComponentInterface) {
|
||||
$host = $host->value();
|
||||
}
|
||||
|
||||
if (null === $host) {
|
||||
return new self(
|
||||
value: null,
|
||||
type: HostType::RegisteredName,
|
||||
format: HostFormat::Ascii,
|
||||
);
|
||||
}
|
||||
|
||||
$host = (string) $host;
|
||||
if ('' === $host) {
|
||||
return new self(
|
||||
value: '',
|
||||
type: HostType::RegisteredName,
|
||||
format: HostFormat::Ascii,
|
||||
);
|
||||
}
|
||||
|
||||
static $inMemoryCache = [];
|
||||
if (isset($inMemoryCache[$host])) {
|
||||
return $inMemoryCache[$host];
|
||||
}
|
||||
|
||||
if (self::MAXIMUM_HOST_CACHED < count($inMemoryCache)) {
|
||||
unset($inMemoryCache[array_key_first($inMemoryCache)]);
|
||||
}
|
||||
|
||||
if ($host === filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
return $inMemoryCache[$host] = new self(
|
||||
value: $host,
|
||||
type: HostType::Ipv4,
|
||||
format: HostFormat::Ascii,
|
||||
);
|
||||
}
|
||||
|
||||
if (str_starts_with($host, '[')) {
|
||||
str_ends_with($host, ']') || throw new SyntaxError('The host '.$host.' is not a valid IPv6 host.');
|
||||
|
||||
$ipHost = substr($host, 1, -1);
|
||||
if (1 === preg_match(self::REGEXP_IP_FUTURE, $ipHost, $matches)) {
|
||||
return !in_array($matches['version'], ['4', '6'], true) ? ($inMemoryCache[$host] = new self(
|
||||
value: $host,
|
||||
type: HostType::IpvFuture,
|
||||
format: HostFormat::Ascii,
|
||||
)) : throw new SyntaxError('The host '.$host.' is not a valid IPvFuture host.');
|
||||
}
|
||||
|
||||
if (self::isValidIpv6Hostname($ipHost)) {
|
||||
return $inMemoryCache[$host] = new self(
|
||||
value: $host,
|
||||
type: HostType::Ipv6,
|
||||
format: HostFormat::Ascii,
|
||||
);
|
||||
}
|
||||
|
||||
throw new SyntaxError('The host '.$host.' is not a valid IPv6 host.');
|
||||
}
|
||||
|
||||
$domainName = rawurldecode($host);
|
||||
$format = HostFormat::Unicode;
|
||||
if (1 !== preg_match(self::REGEXP_NON_ASCII_PATTERN, $domainName)) {
|
||||
$domainName = strtolower($domainName);
|
||||
$format = HostFormat::Ascii;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_REGISTERED_NAME, $domainName)) {
|
||||
return $inMemoryCache[$host] = new self(
|
||||
value: $host,
|
||||
type: HostType::RegisteredName,
|
||||
format: $format,
|
||||
);
|
||||
}
|
||||
|
||||
(HostFormat::Ascii !== $format && 1 !== preg_match(self::REGEXP_INVALID_HOST_CHARS, $domainName)) || throw new SyntaxError('`'.$host.'` is an invalid domain name : the host contains invalid characters.');
|
||||
IdnConverter::toAsciiOrFail($domainName);
|
||||
|
||||
return $inMemoryCache[$host] = new self(
|
||||
value: $host,
|
||||
type: HostType::RegisteredName,
|
||||
format: $format,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the registered name is a valid domain name according to RFC1123.
|
||||
*
|
||||
* @see http://man7.org/linux/man-pages/man7/hostname.7.html
|
||||
* @see https://tools.ietf.org/html/rfc1123#section-2.1
|
||||
*/
|
||||
private static function isValidDomain(string $hostname): bool
|
||||
{
|
||||
$domainMaxLength = str_ends_with($hostname, '.') ? 254 : 253;
|
||||
|
||||
return !isset($hostname[$domainMaxLength])
|
||||
&& 1 === preg_match(self::REGEXP_DOMAIN_NAME, $hostname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an Ipv6 as Host.
|
||||
*
|
||||
* @see http://tools.ietf.org/html/rfc6874#section-2
|
||||
* @see http://tools.ietf.org/html/rfc6874#section-4
|
||||
*/
|
||||
private static function isValidIpv6Hostname(string $host): bool
|
||||
{
|
||||
[$ipv6, $scope] = explode('%', $host, 2) + [1 => null];
|
||||
if (null === $scope) {
|
||||
return (bool) filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
||||
}
|
||||
|
||||
$scope = rawurldecode('%'.$scope);
|
||||
|
||||
return 1 !== preg_match(self::REGEXP_NON_ASCII_PATTERN, $scope)
|
||||
&& 1 !== preg_match(self::REGEXP_GEN_DELIMS, $scope)
|
||||
&& false !== filter_var($ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
|
||||
&& str_starts_with((string)inet_pton((string)$ipv6), self::ADDRESS_BLOCK);
|
||||
}
|
||||
|
||||
public function jsonSerialize(): ?string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HostRecordSerializedShape
|
||||
*/
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [['host' => $this->value], []];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HostRecordSerializedShape $data
|
||||
*
|
||||
* @throws Exception|SyntaxError
|
||||
*/
|
||||
public function __unserialize(array $data): void
|
||||
{
|
||||
[$properties] = $data;
|
||||
$record = self::from($properties['host'] ?? throw new Exception('The `host` property is missing from the serialized object.'));
|
||||
//if the Host computed value are already cache this avoid recomputing them
|
||||
foreach (get_object_vars($record) as $prop => $value) {
|
||||
/** @phpstan-ignore-next-line */
|
||||
$this->{$prop} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
vendor/league/uri-interfaces/HostType.php
vendored
Normal file
22
vendor/league/uri-interfaces/HostType.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* League.Uri (https://uri.thephpleague.com)
|
||||
*
|
||||
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
enum HostType
|
||||
{
|
||||
case RegisteredName;
|
||||
case Ipv4;
|
||||
case Ipv6;
|
||||
case IpvFuture;
|
||||
}
|
||||
193
vendor/league/uri-interfaces/UriString.php
vendored
193
vendor/league/uri-interfaces/UriString.php
vendored
@@ -13,8 +13,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace League\Uri;
|
||||
|
||||
use League\Uri\Exceptions\ConversionFailed;
|
||||
use League\Uri\Exceptions\MissingFeature;
|
||||
use Deprecated;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Idna\Converter as IdnaConverter;
|
||||
use Stringable;
|
||||
@@ -29,10 +28,7 @@ use function explode;
|
||||
use function filter_var;
|
||||
use function function_exists;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function inet_pton;
|
||||
use function preg_match;
|
||||
use function rawurldecode;
|
||||
use function sprintf;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
@@ -40,7 +36,6 @@ use function strtolower;
|
||||
use function substr;
|
||||
|
||||
use const FILTER_FLAG_IPV4;
|
||||
use const FILTER_FLAG_IPV6;
|
||||
use const FILTER_VALIDATE_IP;
|
||||
|
||||
/**
|
||||
@@ -118,44 +113,6 @@ final class UriString
|
||||
*/
|
||||
private const REGEXP_URI_SCHEME = '/^([a-z][a-z\d+.-]*)?$/i';
|
||||
|
||||
/**
|
||||
* IPvFuture regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_IP_FUTURE = '/^
|
||||
v(?<version>[A-F0-9])+\.
|
||||
(?:
|
||||
(?<unreserved>[a-z0-9_~\-\.])|
|
||||
(?<sub_delims>[!$&\'()*+,;=:]) # also include the : character
|
||||
)+
|
||||
$/ix';
|
||||
|
||||
/**
|
||||
* General registered name regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_REGISTERED_NAME = '/(?(DEFINE)
|
||||
(?<unreserved>[a-z0-9_~\-]) # . is missing as it is used to separate labels
|
||||
(?<sub_delims>[!$&\'()*+,;=])
|
||||
(?<encoded>%[A-F0-9]{2})
|
||||
(?<reg_name>(?:(?&unreserved)|(?&sub_delims)|(?&encoded))*)
|
||||
)
|
||||
^(?:(?®_name)\.)*(?®_name)\.?$/ix';
|
||||
|
||||
/**
|
||||
* Invalid characters in host regular expression.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_INVALID_HOST_CHARS = '/
|
||||
[:\/?#\[\]@ ] # gen-delims characters as well as the space character
|
||||
/ix';
|
||||
|
||||
/**
|
||||
* Invalid path for URI without scheme and authority regular expression.
|
||||
*
|
||||
@@ -171,31 +128,9 @@ final class UriString
|
||||
*/
|
||||
private const REGEXP_HOST_PORT = ',^(?<host>\[.*\]|[^:]*)(:(?<port>.*))?$,';
|
||||
|
||||
/**
|
||||
* IDN Host detector regular expression.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_IDN_PATTERN = '/[^\x20-\x7f]/';
|
||||
|
||||
/** @var array<string,int> */
|
||||
private const DOT_SEGMENTS = ['.' => 1, '..' => 1];
|
||||
|
||||
/**
|
||||
* Only the address block fe80::/10 can have a Zone ID attach to
|
||||
* let's detect the link local significant 10 bits.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const ZONE_ID_ADDRESS_BLOCK = "\xfe\x80";
|
||||
|
||||
/**
|
||||
* Maximum number of host cached.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private const MAXIMUM_HOST_CACHED = 100;
|
||||
|
||||
/**
|
||||
* Generate an IRI string representation (RFC3987) from its parsed representation
|
||||
* returned by League\UriString::parse() or PHP's parse_url.
|
||||
@@ -304,6 +239,9 @@ final class UriString
|
||||
public static function buildAuthority(array $components): ?string
|
||||
{
|
||||
if (!isset($components['host'])) {
|
||||
(!isset($components['user']) && !isset($components['pass'])) || throw new SyntaxError('The user info component must not be set if the host is not defined.');
|
||||
!isset($components['port']) || throw new SyntaxError('The port component must not be set if the host is not defined.');
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -730,38 +668,11 @@ final class UriString
|
||||
*/
|
||||
private static function filterHost(Stringable|string|null $host): ?string
|
||||
{
|
||||
if (null !== $host) {
|
||||
$host = (string) $host;
|
||||
try {
|
||||
return HostRecord::from($host)->value;
|
||||
} catch (Throwable) {
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid : the IP host is malformed', $host));
|
||||
}
|
||||
|
||||
if (null === $host || '' === $host) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
/** @var array<string, 1> $hostCache */
|
||||
static $hostCache = [];
|
||||
if (isset($hostCache[$host])) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
if (self::MAXIMUM_HOST_CACHED < count($hostCache)) {
|
||||
array_shift($hostCache);
|
||||
}
|
||||
|
||||
if ('[' !== $host[0] || !str_ends_with($host, ']')) {
|
||||
self::filterRegisteredName($host);
|
||||
$hostCache[$host] = 1;
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
if (self::isIpHost(substr($host, 1, -1))) {
|
||||
$hostCache[$host] = 1;
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid : the IP host is malformed', $host));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -772,79 +683,6 @@ final class UriString
|
||||
return null === $scheme || 1 === preg_match('/^[A-Za-z]([-A-Za-z\d+.]+)?$/', (string) $scheme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the host component is valid.
|
||||
*/
|
||||
public static function isValidHost(Stringable|string|null $host): bool
|
||||
{
|
||||
try {
|
||||
self::filterHost($host);
|
||||
return true;
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws if the host is not a registered name and not a valid IDN host.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @throws SyntaxError if the registered name is invalid
|
||||
* @throws MissingFeature if IDN support or ICU requirement, are not available or met.
|
||||
* @throws ConversionFailed if the submitted IDN host cannot be converted to a valid ascii form
|
||||
*/
|
||||
private static function filterRegisteredName(string $host): void
|
||||
{
|
||||
$formattedHost = rawurldecode($host);
|
||||
if ($formattedHost !== $host) {
|
||||
if (IdnaConverter::toAscii($formattedHost)->hasErrors()) {
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid: the host is not a valid registered name', $host));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_REGISTERED_NAME, $formattedHost)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//to test IDN host non-ascii characters must be present in the host
|
||||
if (1 !== preg_match(self::REGEXP_IDN_PATTERN, $formattedHost)) {
|
||||
throw new SyntaxError(sprintf('Host `%s` is invalid: the host is not a valid registered name', $host));
|
||||
}
|
||||
|
||||
IdnaConverter::toAsciiOrFail($host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a IPv6/IPfuture host.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
* @link https://tools.ietf.org/html/rfc6874#section-2
|
||||
* @link https://tools.ietf.org/html/rfc6874#section-4
|
||||
*/
|
||||
private static function isIpHost(string $ipHost): bool
|
||||
{
|
||||
if (false !== filter_var($ipHost, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_IP_FUTURE, $ipHost, $matches)) {
|
||||
return !in_array($matches['version'], ['4', '6'], true);
|
||||
}
|
||||
|
||||
$pos = strpos($ipHost, '%');
|
||||
if (false === $pos || 1 === preg_match(self::REGEXP_INVALID_HOST_CHARS, rawurldecode(substr($ipHost, $pos)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ipHost = substr($ipHost, 0, $pos);
|
||||
|
||||
return false !== filter_var($ipHost, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)
|
||||
&& str_starts_with((string)inet_pton($ipHost), self::ZONE_ID_ADDRESS_BLOCK);
|
||||
}
|
||||
|
||||
private static function normalizeHost(?string $host): ?string
|
||||
{
|
||||
if (null === $host || false !== filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||
@@ -865,4 +703,19 @@ final class UriString
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATION WARNING! This method will be removed in the next major point release.
|
||||
*
|
||||
* @deprecated Since version 7.6.0
|
||||
* @codeCoverageIgnore
|
||||
* @see HostRecoord::validate()
|
||||
*
|
||||
* Create a new instance from the environment.
|
||||
*/
|
||||
#[Deprecated(message:'use League\Uri\HostRecord::validate() instead', since:'league/uri:7.6.0')]
|
||||
public static function isValidHost(Stringable|string|null $host): bool
|
||||
{
|
||||
return HostRecord::isValid($host);
|
||||
}
|
||||
}
|
||||
|
||||
31
vendor/league/uri/BaseUri.php
vendored
31
vendor/league/uri/BaseUri.php
vendored
@@ -33,6 +33,8 @@ use function implode;
|
||||
use function in_array;
|
||||
use function preg_match;
|
||||
use function rawurldecode;
|
||||
use function sort;
|
||||
use function str_contains;
|
||||
use function str_repeat;
|
||||
use function str_replace;
|
||||
use function strpos;
|
||||
@@ -263,21 +265,32 @@ class BaseUri implements Stringable, JsonSerializable, UriAccess
|
||||
*/
|
||||
public function isSameDocument(Stringable|string $uri): bool
|
||||
{
|
||||
return self::normalizedUri($this->uri)->isSameDocument(self::normalizedUri($uri));
|
||||
return self::normalizedUri($this->uri)->equals(self::normalizedUri($uri));
|
||||
}
|
||||
|
||||
private static function normalizedUri(Stringable|string $uri): Uri
|
||||
{
|
||||
$uri = ($uri instanceof Uri) ? $uri : Uri::new($uri);
|
||||
$host = $uri->getHost();
|
||||
if (null === $host || Ipv4Converter::fromEnvironment()->isIpv4($host) || IPv6Converter::isIpv6($host)) {
|
||||
return $uri;
|
||||
}
|
||||
// Normalize the URI according to RFC3986
|
||||
$uri = ($uri instanceof Uri ? $uri : Uri::new($uri))->normalize();
|
||||
|
||||
/** @var Uri $uri */
|
||||
$uri = $uri->withHost(IdnaConverter::toUnicode((string) Ipv6Converter::compress($host))->domain());
|
||||
return $uri
|
||||
//Normalization as per WHATWG URL standard
|
||||
//only meaningful for WHATWG Special URI scheme protocol
|
||||
->when(
|
||||
condition: '' === $uri->getPath() && null !== $uri->getAuthority(),
|
||||
onSuccess: fn (Uri $uri) => $uri->withPath('/'),
|
||||
)
|
||||
//Sorting as per WHATWG URLSearchParams class
|
||||
//not included on any equivalence algorithm
|
||||
->when(
|
||||
condition: null !== ($query = $uri->getQuery()) && str_contains($query, '&'),
|
||||
onSuccess: function (Uri $uri) use ($query) {
|
||||
$pairs = explode('&', (string) $query);
|
||||
sort($pairs);
|
||||
|
||||
return $uri;
|
||||
return $uri->withQuery(implode('&', $pairs));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
212
vendor/league/uri/Uri.php
vendored
212
vendor/league/uri/Uri.php
vendored
@@ -21,7 +21,6 @@ use League\Uri\Contracts\FragmentDirective;
|
||||
use League\Uri\Contracts\UriComponentInterface;
|
||||
use League\Uri\Contracts\UriException;
|
||||
use League\Uri\Contracts\UriInterface;
|
||||
use League\Uri\Exceptions\ConversionFailed;
|
||||
use League\Uri\Exceptions\MissingFeature;
|
||||
use League\Uri\Exceptions\SyntaxError;
|
||||
use League\Uri\Idna\Converter as IdnaConverter;
|
||||
@@ -43,22 +42,29 @@ use function array_filter;
|
||||
use function array_key_last;
|
||||
use function array_map;
|
||||
use function array_pop;
|
||||
use function array_shift;
|
||||
use function base64_decode;
|
||||
use function base64_encode;
|
||||
use function basename;
|
||||
use function count;
|
||||
use function dirname;
|
||||
use function explode;
|
||||
use function fclose;
|
||||
use function feof;
|
||||
use function file_get_contents;
|
||||
use function filter_var;
|
||||
use function fopen;
|
||||
use function fread;
|
||||
use function fwrite;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function in_array;
|
||||
use function inet_pton;
|
||||
use function is_bool;
|
||||
use function is_object;
|
||||
use function is_resource;
|
||||
use function is_string;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function preg_replace_callback;
|
||||
use function rawurldecode;
|
||||
use function rawurlencode;
|
||||
@@ -79,7 +85,6 @@ use function trim;
|
||||
use const FILEINFO_MIME;
|
||||
use const FILEINFO_MIME_TYPE;
|
||||
use const FILTER_FLAG_IPV4;
|
||||
use const FILTER_FLAG_IPV6;
|
||||
use const FILTER_NULL_ON_FAILURE;
|
||||
use const FILTER_VALIDATE_BOOLEAN;
|
||||
use const FILTER_VALIDATE_EMAIL;
|
||||
@@ -100,43 +105,6 @@ final class Uri implements Conditionable, UriInterface
|
||||
*/
|
||||
private const REGEXP_INVALID_CHARS = '/[\x00-\x1f\x7f]/';
|
||||
|
||||
/**
|
||||
* RFC3986 host identified by a registered name regular expression pattern.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_HOST_REGNAME = '/^(
|
||||
(?<unreserved>[a-z\d_~\-\.])|
|
||||
(?<sub_delims>[!$&\'()*+,;=])|
|
||||
(?<encoded>%[A-F\d]{2})
|
||||
)+$/x';
|
||||
|
||||
/**
|
||||
* RFC3986 delimiters of the generic URI components regular expression pattern.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_HOST_GEN_DELIMS = '/[:\/?#\[\]@ ]/'; // Also includes space.
|
||||
|
||||
/**
|
||||
* RFC3986 IPvFuture regular expression pattern.
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc3986#section-3.2.2
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const REGEXP_HOST_IP_FUTURE = '/^
|
||||
v(?<version>[A-F\d])+\.
|
||||
(?:
|
||||
(?<unreserved>[a-z\d_~\-\.])|
|
||||
(?<sub_delims>[!$&\'()*+,;=:]) # also include the : character
|
||||
)+
|
||||
$/ix';
|
||||
|
||||
/**
|
||||
* RFC3986 IPvFuture host and port component.
|
||||
*
|
||||
@@ -144,13 +112,6 @@ final class Uri implements Conditionable, UriInterface
|
||||
*/
|
||||
private const REGEXP_HOST_PORT = ',^(?<host>(\[.*]|[^:])*)(:(?<port>[^/?#]*))?$,x';
|
||||
|
||||
/**
|
||||
* Significant 10 bits of IP to detect Zone ID regular expression pattern.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private const HOST_ADDRESS_BLOCK = "\xfe\x80";
|
||||
|
||||
/**
|
||||
* Regular expression pattern to for file URI.
|
||||
* <volume> contains the volume but not the volume separator.
|
||||
@@ -230,11 +191,17 @@ final class Uri implements Conditionable, UriInterface
|
||||
$this->pass = Encoder::encodePassword($pass);
|
||||
$this->host = $this->formatHost($host);
|
||||
$this->port = $this->formatPort($port);
|
||||
$this->authority = UriString::buildAuthority([
|
||||
'scheme' => $this->scheme,
|
||||
'user' => $this->user,
|
||||
'pass' => $this->pass,
|
||||
'host' => $this->host,
|
||||
'port' => $this->port,
|
||||
]);
|
||||
$this->path = $this->formatPath($path);
|
||||
$this->query = Encoder::encodeQueryOrFragment($query);
|
||||
$this->fragment = Encoder::encodeQueryOrFragment($fragment);
|
||||
$this->userInfo = null !== $this->pass ? $this->user.':'.$this->pass : $this->user;
|
||||
$this->authority = UriString::buildAuthority($this->toComponents());
|
||||
$this->uriAsciiString = UriString::buildUri($this->scheme, $this->authority, $this->path, $this->query, $this->fragment);
|
||||
$this->assertValidRfc3986Uri();
|
||||
$this->assertValidState();
|
||||
@@ -286,88 +253,7 @@ final class Uri implements Conditionable, UriInterface
|
||||
*/
|
||||
private function formatHost(?string $host): ?string
|
||||
{
|
||||
if (null === $host || '' === $host) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
static $cache = [];
|
||||
if (isset($cache[$host])) {
|
||||
return $cache[$host];
|
||||
}
|
||||
|
||||
$formattedHost = '[' === $host[0] ? $this->formatIp($host) : $this->formatRegisteredName($host);
|
||||
$cache[$host] = $formattedHost;
|
||||
if (self::MAXIMUM_CACHED_ITEMS < count($cache)) {
|
||||
array_shift($cache);
|
||||
}
|
||||
|
||||
return $formattedHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and format a registered name.
|
||||
*
|
||||
* The host is converted to its ascii representation if needed
|
||||
*
|
||||
* @throws MissingFeature if the submitted host required missing or misconfigured IDN support
|
||||
* @throws SyntaxError if the submitted host is not a valid registered name
|
||||
* @throws ConversionFailed if the submitted IDN host cannot be converted to a valid ascii form
|
||||
*/
|
||||
private function formatRegisteredName(string $host): string
|
||||
{
|
||||
$formattedHost = rawurldecode($host);
|
||||
if ($formattedHost === $host) {
|
||||
return match (1) {
|
||||
preg_match(self::REGEXP_HOST_REGNAME, $formattedHost) => $formattedHost,
|
||||
preg_match(self::REGEXP_HOST_GEN_DELIMS, $formattedHost) => throw new SyntaxError('The host `'.$host.'` is invalid : a registered name cannot contain URI delimiters or spaces.'),
|
||||
default => IdnaConverter::toAsciiOrFail($host),
|
||||
};
|
||||
}
|
||||
|
||||
if (IdnaConverter::toAscii($formattedHost)->hasErrors()) {
|
||||
throw new SyntaxError('The host `'.$host.'` is invalid : the registered name contains invalid characters.');
|
||||
}
|
||||
|
||||
return (string) Encoder::normalizeHost($host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and Format the IPv6/IPvfuture host.
|
||||
*
|
||||
* @throws SyntaxError if the submitted host is not a valid IP host
|
||||
*/
|
||||
private function formatIp(string $host): string
|
||||
{
|
||||
$ip = substr($host, 1, -1);
|
||||
if (false !== filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_HOST_IP_FUTURE, $ip, $matches) && !in_array($matches['version'], ['4', '6'], true)) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
$pos = strpos($ip, '%');
|
||||
if (false === $pos) {
|
||||
throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
|
||||
}
|
||||
|
||||
if (1 === preg_match(self::REGEXP_HOST_GEN_DELIMS, rawurldecode(substr($ip, $pos)))) {
|
||||
throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
|
||||
}
|
||||
|
||||
$ip = substr($ip, 0, $pos);
|
||||
if (false === filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||
throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
|
||||
}
|
||||
|
||||
//Only the address block fe80::/10 can have a Zone ID attach to
|
||||
//let's detect the link local significant 10 bits
|
||||
if (str_starts_with((string)inet_pton($ip), self::HOST_ADDRESS_BLOCK)) {
|
||||
return $host;
|
||||
}
|
||||
|
||||
throw new SyntaxError('The host `'.$host.'` is invalid : the IP host is malformed.');
|
||||
return HostRecord::from($host)->toAscii();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -620,8 +506,8 @@ final class Uri implements Conditionable, UriInterface
|
||||
|
||||
return match ([]) {
|
||||
array_filter(explode(';', $parameters), $isInvalidParameter) => self::fromComponents([
|
||||
'scheme' => 'data',
|
||||
'path' => self::formatDataPath($mimetype.';'.$parameters.','.rawurlencode($data)),
|
||||
'scheme' => 'data',
|
||||
'path' => self::formatDataPath($mimetype.';'.$parameters.','.rawurlencode($data)),
|
||||
]),
|
||||
default => throw new SyntaxError(sprintf('Invalid mediatype parameters, `%s`.', $parameters))
|
||||
};
|
||||
@@ -797,11 +683,37 @@ final class Uri implements Conditionable, UriInterface
|
||||
*/
|
||||
private function formatPath(string $path): string
|
||||
{
|
||||
return match ($this->scheme) {
|
||||
$path = match ($this->scheme) {
|
||||
'data' => Encoder::encodePath(self::formatDataPath($path)),
|
||||
'file' => self::formatFilePath(Encoder::encodePath($path)),
|
||||
default => Encoder::encodePath($path),
|
||||
};
|
||||
|
||||
if ('' === $path) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
if (null !== $this->authority) {
|
||||
// If there is an authority, the path must start with a `/`
|
||||
return str_starts_with($path, '/') ? $path : '/'.$path;
|
||||
}
|
||||
|
||||
// If there is no authority, the path cannot start with `//`
|
||||
if (str_starts_with($path, '//')) {
|
||||
return '/.'.$path;
|
||||
}
|
||||
|
||||
$colonPos = strpos($path, ':');
|
||||
if (false !== $colonPos && null === $this->scheme) {
|
||||
// In the absence of a scheme and of an authority,
|
||||
// the first path segment cannot contain a colon (":") character.'
|
||||
$slashPos = strpos($path, '/');
|
||||
(false !== $slashPos && $colonPos > $slashPos) || throw new SyntaxError(
|
||||
'In absence of the scheme and authority components, the first path segment cannot contain a colon (":") character.'
|
||||
);
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -903,7 +815,7 @@ final class Uri implements Conditionable, UriInterface
|
||||
}
|
||||
|
||||
if (null === $this->authority && str_starts_with($this->path, '//')) {
|
||||
throw new SyntaxError('If there is no authority the path `' . $this->path . '` cannot start with a `//`.');
|
||||
throw new SyntaxError('If there is no authority the path `'.$this->path.'` cannot start with a `//`.');
|
||||
}
|
||||
|
||||
$pos = strpos($this->path, ':');
|
||||
@@ -917,7 +829,7 @@ final class Uri implements Conditionable, UriInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* assert the URI scheme is valid
|
||||
* assert the URI scheme is valid.
|
||||
*
|
||||
* @link https://w3c.github.io/FileAPI/#url
|
||||
* @link https://datatracker.ietf.org/doc/html/rfc2397
|
||||
@@ -1400,6 +1312,36 @@ final class Uri implements Conditionable, UriInterface
|
||||
return $host;
|
||||
}
|
||||
|
||||
public function isIpv4Host(): bool
|
||||
{
|
||||
return HostRecord::isIpv4($this->host);
|
||||
}
|
||||
|
||||
public function isIpv6Host(): bool
|
||||
{
|
||||
return HostRecord::isIpv6($this->host);
|
||||
}
|
||||
|
||||
public function isIpvFutureHost(): bool
|
||||
{
|
||||
return HostRecord::isIpvFuture($this->host);
|
||||
}
|
||||
|
||||
public function isIpHost(): bool
|
||||
{
|
||||
return HostRecord::isIp($this->host);
|
||||
}
|
||||
|
||||
public function isRegisteredNameHost(): bool
|
||||
{
|
||||
return HostRecord::isRegisteredName($this->host);
|
||||
}
|
||||
|
||||
public function isDomainHost(): bool
|
||||
{
|
||||
return HostRecord::isDomain($this->host);
|
||||
}
|
||||
|
||||
public function getPort(): ?int
|
||||
{
|
||||
return $this->port;
|
||||
|
||||
16
vendor/league/uri/UriTemplate.php
vendored
16
vendor/league/uri/UriTemplate.php
vendored
@@ -147,7 +147,7 @@ final class UriTemplate implements Stringable
|
||||
*/
|
||||
public function expandToUri(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUri = null): Rfc3986Uri
|
||||
{
|
||||
class_exists(Rfc3986Uri::class) || throw new MissingFeature('Support for '.Rfc3986Uri::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you owm polyfill.');
|
||||
class_exists(Rfc3986Uri::class) || throw new MissingFeature('Support for '.Rfc3986Uri::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you own polyfill.');
|
||||
|
||||
return new Rfc3986Uri($this->templateExpanded($variables), $this->newRfc3986Uri($baseUri));
|
||||
}
|
||||
@@ -158,11 +158,11 @@ final class UriTemplate implements Stringable
|
||||
* @throws InvalidUrlException if the base URI cannot be converted to a Uri\Whatwg\Url instance
|
||||
* @throws InvalidUrlException if the resulting expansion cannot be converted to a Uri\Whatwg\Url instance
|
||||
*/
|
||||
public function expandToUrl(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUrl = null): WhatWgUrl
|
||||
public function expandToUrl(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUrl = null, array|null &$errors = []): WhatWgUrl
|
||||
{
|
||||
class_exists(WhatWgUrl::class) || throw new MissingFeature('Support for '.WhatWgUrl::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you owm polyfill.');
|
||||
class_exists(WhatWgUrl::class) || throw new MissingFeature('Support for '.WhatWgUrl::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you own polyfill.');
|
||||
|
||||
return new WhatWgUrl($this->templateExpanded($variables), $this->newWhatWgUrl($baseUrl));
|
||||
return new WhatWgUrl($this->templateExpanded($variables), $this->newWhatWgUrl($baseUrl), $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +206,7 @@ final class UriTemplate implements Stringable
|
||||
*/
|
||||
public function expandToUriOrFail(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUri = null): Rfc3986Uri
|
||||
{
|
||||
class_exists(Rfc3986Uri::class) || throw new MissingFeature('Support for '.Rfc3986Uri::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you owm polyfill.');
|
||||
class_exists(Rfc3986Uri::class) || throw new MissingFeature('Support for '.Rfc3986Uri::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you own polyfill.');
|
||||
|
||||
return new Rfc3986Uri($this->templateExpandedOrFail($variables), $this->newRfc3986Uri($baseUri));
|
||||
}
|
||||
@@ -217,11 +217,11 @@ final class UriTemplate implements Stringable
|
||||
* @throws InvalidUrlException if the base URI cannot be converted to a Uri\Whatwg\Url instance
|
||||
* @throws InvalidUrlException if the resulting expansion cannot be converted to a Uri\Whatwg\Url instance
|
||||
*/
|
||||
public function expandToUrlOrFail(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUrl = null): WhatWgUrl
|
||||
public function expandToUrlOrFail(iterable $variables = [], Rfc3986Uri|WhatWgUrl|Stringable|string|null $baseUrl = null, array|null &$errors = []): WhatWgUrl
|
||||
{
|
||||
class_exists(WhatWgUrl::class) || throw new MissingFeature('Support for '.WhatWgUrl::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you owm polyfill.');
|
||||
class_exists(WhatWgUrl::class) || throw new MissingFeature('Support for '.WhatWgUrl::class.' requires PHP8.5+ or a polyfill. Run "composer require league/uri-polyfill" or use you own polyfill.');
|
||||
|
||||
return new WhatWgUrl($this->templateExpandedOrFail($variables), $this->newWhatWgUrl($baseUrl));
|
||||
return new WhatWgUrl($this->templateExpandedOrFail($variables), $this->newWhatWgUrl($baseUrl), $errors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
2
vendor/league/uri/composer.json
vendored
2
vendor/league/uri/composer.json
vendored
@@ -48,7 +48,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.1",
|
||||
"league/uri-interfaces": "^7.6",
|
||||
"league/uri-interfaces": "^7.7",
|
||||
"psr/http-factory": "^1"
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
@@ -115,6 +115,20 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve
|
||||
return self::sk_to_pk($sk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if $A represents a point on the order of the Edwards25519 prime order subgroup.
|
||||
* Returns FALSE if $A is on a different subgroup.
|
||||
*
|
||||
* @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_on_main_subgroup(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A): bool
|
||||
{
|
||||
$p1 = self::ge_mul_l($A);
|
||||
$t = self::fe_sub($p1->Y, $p1->Z);
|
||||
return self::fe_isnonzero($p1->X) && self::fe_isnonzero($t);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $pk
|
||||
* @return string
|
||||
@@ -131,9 +145,9 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve
|
||||
throw new SodiumException('Public key is on a small order');
|
||||
}
|
||||
$A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32));
|
||||
$p1 = self::ge_mul_l($A);
|
||||
if (!self::fe_isnonzero($p1->X)) {
|
||||
throw new SodiumException('Unexpected zero result');
|
||||
// check that A * L == identity point
|
||||
if (!self::is_on_main_subgroup($A)) {
|
||||
throw new SodiumException('Public key is not on a member of the main subgroup');
|
||||
}
|
||||
$one_minux_y = self::fe_invert(
|
||||
self::fe_sub(
|
||||
@@ -283,7 +297,7 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve
|
||||
throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long');
|
||||
}
|
||||
if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
|
||||
throw new SodiumException('S < L - Invalid signature');
|
||||
throw new SodiumException('S >= L - Invalid signature');
|
||||
}
|
||||
if (self::small_order($sig)) {
|
||||
throw new SodiumException('Signature is on too small of an order');
|
||||
@@ -306,6 +320,9 @@ abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve
|
||||
ParagonIE_Sodium_Compat::$fastMult = true;
|
||||
|
||||
$A = self::ge_frombytes_negate_vartime($pk);
|
||||
if (!self::is_on_main_subgroup($A)) {
|
||||
throw new SodiumException('Public key is not on main subgroup');
|
||||
}
|
||||
|
||||
$hDigest = hash(
|
||||
'sha512',
|
||||
|
||||
6
vendor/paragonie/sodium_compat/src/File.php
vendored
6
vendor/paragonie/sodium_compat/src/File.php
vendored
@@ -630,6 +630,12 @@ class ParagonIE_Sodium_File extends ParagonIE_Sodium_Core_Util
|
||||
ParagonIE_Sodium_Compat::$fastMult = true;
|
||||
|
||||
$A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey);
|
||||
if (ParagonIE_Sodium_Core_Ed25519::small_order($publicKey)) {
|
||||
throw new SodiumException('Public key has small order');
|
||||
}
|
||||
if (!ParagonIE_Sodium_Core_Ed25519::is_on_main_subgroup($A)) {
|
||||
throw new SodiumException('Public key is not on main subgroup');
|
||||
}
|
||||
|
||||
$hs = hash_init('sha512');
|
||||
hash_update($hs, self::substr($sig, 0, 32));
|
||||
|
||||
3
vendor/phpseclib/phpseclib/BACKERS.md
vendored
3
vendor/phpseclib/phpseclib/BACKERS.md
vendored
@@ -16,4 +16,5 @@ phpseclib ongoing development is made possible by [Tidelift](https://tidelift.co
|
||||
- [istiak-tridip](https://github.com/istiak-tridip)
|
||||
- [Anna Filina](https://github.com/afilina)
|
||||
- [blakemckeeby](https://github.com/blakemckeeby)
|
||||
- [ssddanbrown](https://github.com/ssddanbrown)
|
||||
- [ssddanbrown](https://github.com/ssddanbrown)
|
||||
- Stefan Beck
|
||||
4
vendor/phpseclib/phpseclib/README.md
vendored
4
vendor/phpseclib/phpseclib/README.md
vendored
@@ -51,7 +51,7 @@ SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 /
|
||||
* PHP4 compatible
|
||||
* Composer compatible (PSR-0 autoloading)
|
||||
* Install using Composer: `composer require phpseclib/phpseclib:~1.0`
|
||||
* [Download 1.0.24 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.24.zip/download)
|
||||
* [Download 1.0.25 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.25.zip/download)
|
||||
|
||||
## Security contact information
|
||||
|
||||
@@ -75,6 +75,8 @@ Need Support?
|
||||
## Additional Thanks
|
||||
|
||||
- Allan Simon
|
||||
- [Anna Filina](https://afilina.com/)
|
||||
- delovelady
|
||||
- [ChargeOver](https://chargeover.com/)
|
||||
- <a href="https://jb.gg/OpenSource"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg" height="20px"></a>
|
||||
|
||||
|
||||
13
vendor/phpseclib/phpseclib/SECURITY.md
vendored
Normal file
13
vendor/phpseclib/phpseclib/SECURITY.md
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.0.x | :white_check_mark: |
|
||||
| 2.0.x | :white_check_mark: |
|
||||
| 3.0.x | :white_check_mark: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure.
|
||||
@@ -141,7 +141,7 @@ abstract class PSS extends Progenitor
|
||||
$result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']);
|
||||
$result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']);
|
||||
if (isset($params['saltLength'])) {
|
||||
$result['saltLength'] = (int) $params['saltLength']->toString();
|
||||
$result['saltLength'] = (int) "$params[saltLength]";
|
||||
}
|
||||
|
||||
if (isset($key['meta'])) {
|
||||
|
||||
@@ -789,7 +789,10 @@ abstract class ASN1
|
||||
case self::TYPE_ENUMERATED:
|
||||
$temp = $decoded['content'];
|
||||
if (isset($mapping['implicit'])) {
|
||||
$temp = new BigInteger($decoded['content'], -256);
|
||||
$temp = new BigInteger($temp, -256);
|
||||
}
|
||||
if (!$temp instanceof BigInteger) {
|
||||
return false;
|
||||
}
|
||||
if (isset($mapping['mapping'])) {
|
||||
$temp = $temp->toString();
|
||||
|
||||
@@ -154,7 +154,7 @@ class BCMath extends Engine
|
||||
|
||||
while (bccomp($current, '0', 0) > 0) {
|
||||
$temp = self::BCMOD_THREE_PARAMS ? bcmod($current, '16777216', 0) : bcmod($current, '16777216');
|
||||
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
|
||||
$value = chr($temp >> 16) . chr(($temp >> 8) & 0xFF) . chr($temp & 0xFF) . $value;
|
||||
$current = bcdiv($current, '16777216', 0);
|
||||
}
|
||||
|
||||
|
||||
303
vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
vendored
Normal file
303
vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php
vendored
Normal file
@@ -0,0 +1,303 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of SCP.
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
|
||||
*
|
||||
* Here's a short example of how to use this library:
|
||||
* <code>
|
||||
* <?php
|
||||
* include 'vendor/autoload.php';
|
||||
*
|
||||
* $scp = new \phpseclib3\Net\SCP('www.domain.tld');
|
||||
* if (!$scp->login('username', 'password')) {
|
||||
* exit('Login Failed');
|
||||
* }
|
||||
*
|
||||
* echo $scp->exec('pwd') . "\r\n";
|
||||
* $scp->put('filename.ext', 'hello, world!');
|
||||
* echo $scp->exec('ls -latr');
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2009 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib3\Net;
|
||||
|
||||
use phpseclib3\Common\Functions\Strings;
|
||||
use phpseclib3\Exception\FileNotFoundException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementations of SCP.
|
||||
*
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class SCP extends SSH2
|
||||
{
|
||||
/**
|
||||
* Reads data from a local file.
|
||||
*
|
||||
* @see \phpseclib3\Net\SCP::put()
|
||||
*/
|
||||
const SOURCE_LOCAL_FILE = 1;
|
||||
/**
|
||||
* Reads data from a string.
|
||||
*
|
||||
* @see \phpseclib3\Net\SCP::put()
|
||||
*/
|
||||
// this value isn't really used anymore but i'm keeping it reserved for historical reasons
|
||||
const SOURCE_STRING = 2;
|
||||
/**
|
||||
* SCP.php doesn't support SOURCE_CALLBACK because, with that one, we don't know the size, in advance
|
||||
*/
|
||||
//const SOURCE_CALLBACK = 16;
|
||||
|
||||
/**
|
||||
* Error information
|
||||
*
|
||||
* @see self::getSCPErrors()
|
||||
* @see self::getLastSCPError()
|
||||
* @var array
|
||||
*/
|
||||
private $scp_errors = [];
|
||||
|
||||
/**
|
||||
* Uploads a file to the SCP server.
|
||||
*
|
||||
* By default, \phpseclib\Net\SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
|
||||
* So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SCP::get(), you will get a file, twelve bytes
|
||||
* long, containing 'filename.ext' as its contents.
|
||||
*
|
||||
* Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will
|
||||
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
|
||||
* large $remote_file will be, as well.
|
||||
*
|
||||
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
|
||||
* care of that, yourself.
|
||||
*
|
||||
* @param string $remote_file
|
||||
* @param string $data
|
||||
* @param int $mode
|
||||
* @param callable $callback
|
||||
* @return bool
|
||||
* @access public
|
||||
*/
|
||||
public function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($remote_file)) {
|
||||
// remote file cannot be blank
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to
|
||||
return false;
|
||||
}
|
||||
|
||||
$temp = $this->get_channel_packet(self::CHANNEL_EXEC, true);
|
||||
if ($temp !== chr(0)) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
$packet_size = $this->packet_size_client_to_server[self::CHANNEL_EXEC] - 4;
|
||||
|
||||
$remote_file = basename($remote_file);
|
||||
|
||||
$dataCallback = false;
|
||||
switch (true) {
|
||||
case is_resource($data):
|
||||
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
|
||||
$info = stream_get_meta_data($data);
|
||||
if (isset($info['wrapper_type']) && $info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
|
||||
$fp = fopen('php://memory', 'w+');
|
||||
stream_copy_to_stream($data, $fp);
|
||||
rewind($fp);
|
||||
} else {
|
||||
$fp = $data;
|
||||
}
|
||||
break;
|
||||
case $mode & self::SOURCE_LOCAL_FILE:
|
||||
if (!is_file($data)) {
|
||||
throw new FileNotFoundException("$data is not a valid file");
|
||||
}
|
||||
$fp = @fopen($data, 'rb');
|
||||
if (!$fp) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($fp)) {
|
||||
$stat = fstat($fp);
|
||||
$size = !empty($stat) ? $stat['size'] : 0;
|
||||
} else {
|
||||
$size = strlen($data);
|
||||
}
|
||||
|
||||
$sent = 0;
|
||||
$size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
|
||||
|
||||
$temp = 'C0644 ' . $size . ' ' . $remote_file . "\n";
|
||||
$this->send_channel_packet(self::CHANNEL_EXEC, $temp);
|
||||
|
||||
$temp = $this->get_channel_packet(self::CHANNEL_EXEC, true);
|
||||
if ($temp !== chr(0)) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
$sent = 0;
|
||||
while ($sent < $size) {
|
||||
$temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $packet_size) : fread($fp, $packet_size);
|
||||
$this->send_channel_packet(self::CHANNEL_EXEC, $temp);
|
||||
$sent += strlen($temp);
|
||||
|
||||
if (is_callable($callback)) {
|
||||
call_user_func($callback, $sent);
|
||||
}
|
||||
}
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
|
||||
if ($mode != self::SOURCE_STRING) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a file from the SCP server.
|
||||
*
|
||||
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
|
||||
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
|
||||
* operation
|
||||
*
|
||||
* @param string $remote_file
|
||||
* @param string $local_file
|
||||
* @return mixed
|
||||
* @access public
|
||||
*/
|
||||
public function get($remote_file, $local_file = null, $progressCallback = null)
|
||||
{
|
||||
if (!($this->bitmap & self::MASK_LOGIN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->send_channel_packet(self::CHANNEL_EXEC, chr(0));
|
||||
|
||||
$info = $this->get_channel_packet(self::CHANNEL_EXEC, true);
|
||||
// per https://goteleport.com/blog/scp-familiar-simple-insecure-slow/ non-zero responses mean there are errors
|
||||
if ($info[0] === chr(1) || $info[0] == chr(2)) {
|
||||
$type = $info[0] === chr(1) ? 'warning' : 'error';
|
||||
$this->scp_errors[] = "$type: " . substr($info, 1);
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->send_channel_packet(self::CHANNEL_EXEC, chr(0));
|
||||
|
||||
if (!preg_match('#(?<perms>[^ ]+) (?<size>\d+) (?<name>.+)#', rtrim($info), $info)) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
$fclose_check = false;
|
||||
if (is_resource($local_file)) {
|
||||
$fp = $local_file;
|
||||
} elseif (!is_null($local_file)) {
|
||||
$fp = @fopen($local_file, 'wb');
|
||||
if (!$fp) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
$fclose_check = true;
|
||||
} else {
|
||||
$content = '';
|
||||
}
|
||||
|
||||
$size = 0;
|
||||
while (true) {
|
||||
$data = $this->get_channel_packet(self::CHANNEL_EXEC, true);
|
||||
// Terminate the loop in case the server repeatedly sends an empty response
|
||||
if ($data === false) {
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
// no data received from server
|
||||
return false;
|
||||
}
|
||||
// SCP usually seems to split stuff out into 16k chunks
|
||||
$length = strlen($data);
|
||||
$size += $length;
|
||||
$end = $size > $info['size'];
|
||||
if ($end) {
|
||||
$diff = $size - $info['size'];
|
||||
$offset = $length - $diff;
|
||||
if ($data[$offset] === chr(0)) {
|
||||
$data = substr($data, 0, -$diff);
|
||||
} else {
|
||||
$type = $data[$offset] === chr(1) ? 'warning' : 'error';
|
||||
$this->scp_errors[] = "$type: " . substr($data, 1);
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($local_file)) {
|
||||
$content .= $data;
|
||||
} else {
|
||||
fputs($fp, $data);
|
||||
}
|
||||
|
||||
if (is_callable($progressCallback)) {
|
||||
call_user_func($progressCallback, $size);
|
||||
}
|
||||
|
||||
if ($end) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->close_channel(self::CHANNEL_EXEC, true);
|
||||
|
||||
if ($fclose_check) {
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
// if $content isn't set that means a file was written to
|
||||
return isset($content) ? $content : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all errors on the SCP layer
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getSCPErrors()
|
||||
{
|
||||
return $this->scp_errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last error on the SCP layer
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLastSCPError()
|
||||
{
|
||||
return count($this->scp_errors) ? $this->scp_errors[count($this->scp_errors) - 1] : '';
|
||||
}
|
||||
}
|
||||
@@ -3462,7 +3462,6 @@ class SFTP extends SSH2
|
||||
return $this->packet_type_log;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all errors on the SFTP layer
|
||||
*
|
||||
|
||||
@@ -679,7 +679,7 @@ class SSH2
|
||||
* @see self::send_channel_packet()
|
||||
* @var array
|
||||
*/
|
||||
private $packet_size_client_to_server = [];
|
||||
protected $packet_size_client_to_server = [];
|
||||
|
||||
/**
|
||||
* Message Number Log
|
||||
@@ -2941,6 +2941,9 @@ class SSH2
|
||||
$this->channel_id_last_interactive = self::CHANNEL_EXEC;
|
||||
return true;
|
||||
}
|
||||
if ($callback === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$output = '';
|
||||
while (true) {
|
||||
@@ -3997,9 +4000,11 @@ class SSH2
|
||||
break;
|
||||
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
|
||||
Strings::shift($payload, 1);
|
||||
list($request_name) = Strings::unpackSSH2('s', $payload);
|
||||
list($request_name, $want_reply) = Strings::unpackSSH2('sb', $payload);
|
||||
$this->errors[] = "SSH_MSG_GLOBAL_REQUEST: $request_name";
|
||||
$this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE));
|
||||
if ($want_reply) {
|
||||
$this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE));
|
||||
}
|
||||
$payload = $this->get_binary_packet();
|
||||
break;
|
||||
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
|
||||
@@ -4236,7 +4241,6 @@ class SSH2
|
||||
if (strlen($error_message)) {
|
||||
$this->errors[count($this->errors) - 1] .= "\r\n$error_message";
|
||||
}
|
||||
|
||||
if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) {
|
||||
if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) {
|
||||
$this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$channel]));
|
||||
@@ -4245,7 +4249,6 @@ class SSH2
|
||||
|
||||
$this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE;
|
||||
}
|
||||
|
||||
continue 3;
|
||||
case 'exit-status':
|
||||
list(, $this->exit_status) = Strings::unpackSSH2('CN', $response);
|
||||
@@ -4255,8 +4258,13 @@ class SSH2
|
||||
|
||||
continue 3;
|
||||
default:
|
||||
// "Some systems may not implement signals, in which case they SHOULD ignore this message."
|
||||
// -- http://tools.ietf.org/html/rfc4254#section-6.9
|
||||
list($want_reply) = Strings::unpackSSH2('b', $response);
|
||||
if ($want_reply) {
|
||||
// "If the request is not recognized or is not supported for the channel,
|
||||
// SSH_MSG_CHANNEL_FAILURE is returned."
|
||||
// -- https://datatracker.ietf.org/doc/html/rfc4254#page-10
|
||||
$this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_FAILURE, $this->server_channels[$channel]));
|
||||
}
|
||||
continue 3;
|
||||
}
|
||||
}
|
||||
@@ -4714,7 +4722,7 @@ class SSH2
|
||||
* @param bool $want_reply
|
||||
* @return void
|
||||
*/
|
||||
private function close_channel($client_channel)
|
||||
protected function close_channel($client_channel)
|
||||
{
|
||||
// see http://tools.ietf.org/html/rfc4254#section-5.3
|
||||
|
||||
|
||||
2
vendor/ramsey/uuid/composer.json
vendored
2
vendor/ramsey/uuid/composer.json
vendored
@@ -10,7 +10,7 @@
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.0",
|
||||
"brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
|
||||
"ramsey/collection": "^1.2 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
|
||||
@@ -110,7 +110,7 @@ class PhpTimeConverter implements TimeConverterInterface
|
||||
|
||||
// Convert the 100-nanosecond intervals into seconds and microseconds.
|
||||
$splitTime = $this->splitTime(
|
||||
((int) $timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS) / self::SECOND_INTERVALS,
|
||||
($timestamp->toString() - self::GREGORIAN_TO_UNIX_INTERVALS) / self::SECOND_INTERVALS,
|
||||
);
|
||||
|
||||
if (count($splitTime) === 0) {
|
||||
|
||||
@@ -29,7 +29,7 @@ class VEvent extends VObject\Component
|
||||
*/
|
||||
public function isInTimeRange(DateTimeInterface $start, DateTimeInterface $end)
|
||||
{
|
||||
if ($this->RRULE) {
|
||||
if ($this->RRULE || $this->RDATE) {
|
||||
try {
|
||||
$it = new EventIterator($this, null, $start->getTimezone());
|
||||
} catch (NoInstancesException $e) {
|
||||
|
||||
43
vendor/sabre/vobject/lib/ITip/Broker.php
vendored
43
vendor/sabre/vobject/lib/ITip/Broker.php
vendored
@@ -240,16 +240,29 @@ class Broker
|
||||
$baseCalendar = $oldCalendar;
|
||||
}
|
||||
|
||||
// Check if the user is the organizer
|
||||
if (in_array($eventInfo['organizer'], $userHref)) {
|
||||
return $this->parseEventForOrganizer($baseCalendar, $eventInfo, $oldEventInfo);
|
||||
} elseif ($oldCalendar) {
|
||||
// We need to figure out if the user is an attendee, but we're only
|
||||
// doing so if there's an oldCalendar, because we only want to
|
||||
// process updates, not creation of new events.
|
||||
foreach ($eventInfo['attendees'] as $attendee) {
|
||||
if (in_array($attendee['href'], $userHref)) {
|
||||
}
|
||||
|
||||
// Check if the user is an attendee
|
||||
foreach ($eventInfo['attendees'] as $attendee) {
|
||||
if (in_array($attendee['href'], $userHref)) {
|
||||
// If this is a event update, we always generate a reply
|
||||
if ($oldCalendar) {
|
||||
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
|
||||
}
|
||||
|
||||
// If this is a new event, we only generate a reply if the participation status is set
|
||||
foreach ($attendee['instances'] as $instance) {
|
||||
if (isset($instance['partstat']) && 'NEEDS-ACTION' !== $instance['partstat']) {
|
||||
// Attendee has responded (ACCEPTED/DECLINED/TENTATIVE) - generate REPLY
|
||||
return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
|
||||
}
|
||||
}
|
||||
|
||||
// User is attendee but no response to process
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +499,6 @@ class Broker
|
||||
}
|
||||
|
||||
$messages = [];
|
||||
|
||||
foreach ($attendees as $attendee) {
|
||||
// An organizer can also be an attendee. We should not generate any
|
||||
// messages for those.
|
||||
@@ -586,6 +598,9 @@ class Broker
|
||||
));
|
||||
} else {
|
||||
$currentEvent->EXDATE = $exceptions;
|
||||
if ($currentEvent->DTSTART['TZID']) {
|
||||
$currentEvent->EXDATE['TZID'] = clone $currentEvent->DTSTART['TZID'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,14 +609,14 @@ class Broker
|
||||
unset($currentEvent->ORGANIZER['SCHEDULE-FORCE-SEND']);
|
||||
unset($currentEvent->ORGANIZER['SCHEDULE-STATUS']);
|
||||
|
||||
foreach ($currentEvent->ATTENDEE as $attendee) {
|
||||
unset($attendee['SCHEDULE-FORCE-SEND']);
|
||||
unset($attendee['SCHEDULE-STATUS']);
|
||||
foreach ($currentEvent->ATTENDEE as $currentEventAttendee) {
|
||||
unset($currentEventAttendee['SCHEDULE-FORCE-SEND']);
|
||||
unset($currentEventAttendee['SCHEDULE-STATUS']);
|
||||
|
||||
// We're adding PARTSTAT=NEEDS-ACTION to ensure that
|
||||
// iOS shows an "Inbox Item"
|
||||
if (!isset($attendee['PARTSTAT'])) {
|
||||
$attendee['PARTSTAT'] = 'NEEDS-ACTION';
|
||||
if (!isset($currentEventAttendee['PARTSTAT'])) {
|
||||
$currentEventAttendee['PARTSTAT'] = 'NEEDS-ACTION';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -900,6 +915,9 @@ class Broker
|
||||
$timezone = $vevent->{'RECURRENCE-ID'}->getDateTime()->getTimeZone();
|
||||
}
|
||||
}
|
||||
|
||||
$instances[$recurId] = $vevent;
|
||||
|
||||
if (isset($vevent->ATTENDEE)) {
|
||||
foreach ($vevent->ATTENDEE as $attendee) {
|
||||
if ($this->scheduleAgentServerRules &&
|
||||
@@ -938,7 +956,6 @@ class Broker
|
||||
];
|
||||
}
|
||||
}
|
||||
$instances[$recurId] = $vevent;
|
||||
}
|
||||
|
||||
foreach ($this->significantChangeProperties as $prop) {
|
||||
|
||||
25
vendor/sabre/vobject/lib/Parser/MimeDir.php
vendored
25
vendor/sabre/vobject/lib/Parser/MimeDir.php
vendored
@@ -25,6 +25,11 @@ use Sabre\VObject\ParseException;
|
||||
*/
|
||||
class MimeDir extends Parser
|
||||
{
|
||||
public const TOKEN_PROPNAME = 1;
|
||||
public const TOKEN_PROPVALUE = 2;
|
||||
public const TOKEN_PARAMNAME = 3;
|
||||
public const TOKEN_PARAMVALUE = 4;
|
||||
|
||||
/**
|
||||
* The input stream.
|
||||
*
|
||||
@@ -362,6 +367,12 @@ class MimeDir extends Parser
|
||||
'value' => null,
|
||||
];
|
||||
|
||||
/*
|
||||
* Keep track on the last token we parsed in order to do
|
||||
* better error checking
|
||||
*/
|
||||
$lastToken = null;
|
||||
|
||||
$lastParam = null;
|
||||
|
||||
/*
|
||||
@@ -387,10 +398,16 @@ class MimeDir extends Parser
|
||||
// option is set to ignore invalid lines, we ignore this line
|
||||
// This can happen when servers provide faulty data as iCloud
|
||||
// frequently does with X-APPLE-STRUCTURED-LOCATION
|
||||
$lastToken = self::TOKEN_PARAMVALUE;
|
||||
continue;
|
||||
}
|
||||
throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
|
||||
}
|
||||
|
||||
if ('=' == $match[0][0] && self::TOKEN_PARAMNAME != $lastToken) {
|
||||
throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.': Missing parameter name for parameter value "'.$match['paramValue'].'"');
|
||||
}
|
||||
|
||||
if (is_null($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam] = $value;
|
||||
} elseif (is_array($property['parameters'][$lastParam])) {
|
||||
@@ -404,6 +421,7 @@ class MimeDir extends Parser
|
||||
$value,
|
||||
];
|
||||
}
|
||||
$lastToken = self::TOKEN_PARAMVALUE;
|
||||
continue;
|
||||
}
|
||||
if (isset($match['paramName'])) {
|
||||
@@ -411,14 +429,17 @@ class MimeDir extends Parser
|
||||
if (!isset($property['parameters'][$lastParam])) {
|
||||
$property['parameters'][$lastParam] = null;
|
||||
}
|
||||
$lastToken = self::TOKEN_PARAMNAME;
|
||||
continue;
|
||||
}
|
||||
if (isset($match['propValue'])) {
|
||||
$property['value'] = $match['propValue'];
|
||||
$lastToken = self::TOKEN_PROPVALUE;
|
||||
continue;
|
||||
}
|
||||
if (isset($match['name']) && $match['name']) {
|
||||
if (isset($match['name']) && 0 < strlen($match['name'])) {
|
||||
$property['name'] = strtoupper($match['name']);
|
||||
$lastToken = self::TOKEN_PROPNAME;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -430,7 +451,7 @@ class MimeDir extends Parser
|
||||
if (is_null($property['value'])) {
|
||||
$property['value'] = '';
|
||||
}
|
||||
if (!$property['name']) {
|
||||
if (!isset($property['name']) || 0 == strlen($property['name'])) {
|
||||
if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -168,8 +168,12 @@ class EventIterator implements \Iterator
|
||||
}
|
||||
|
||||
if (isset($this->masterEvent->RDATE)) {
|
||||
$rdateValues = [];
|
||||
foreach ($this->masterEvent->RDATE as $rdate) {
|
||||
$rdateValues = array_merge($rdateValues, $rdate->getParts());
|
||||
}
|
||||
$this->recurIterator = new RDateIterator(
|
||||
$this->masterEvent->RDATE->getParts(),
|
||||
$rdateValues,
|
||||
$this->startDate
|
||||
);
|
||||
} elseif (isset($this->masterEvent->RRULE)) {
|
||||
|
||||
2
vendor/sabre/vobject/lib/Version.php
vendored
2
vendor/sabre/vobject/lib/Version.php
vendored
@@ -14,5 +14,5 @@ class Version
|
||||
/**
|
||||
* Full version number.
|
||||
*/
|
||||
public const VERSION = '4.5.7';
|
||||
public const VERSION = '4.5.8';
|
||||
}
|
||||
|
||||
46
vendor/spomky-labs/otphp/CODE_OF_CONDUCT.md
vendored
Normal file
46
vendor/spomky-labs/otphp/CODE_OF_CONDUCT.md
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@spomky-labs.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
4
vendor/spomky-labs/otphp/README.md
vendored
4
vendor/spomky-labs/otphp/README.md
vendored
@@ -32,9 +32,9 @@ Or
|
||||
|
||||
## Contributing
|
||||
|
||||
Requests for new features, bug fixed and all other ideas to make this project useful are welcome.
|
||||
Requests for new features, bug fixes and all other ideas to make this project useful are welcome.
|
||||
|
||||
Please report all issues in [the repository bug tracker](hhttps://github.com/Spomky-Labs/otphp/issues).
|
||||
Please report all issues in [the repository bug tracker](https://github.com/Spomky-Labs/otphp/issues).
|
||||
|
||||
Also make sure to [follow these best practices](.github/CONTRIBUTING.md).
|
||||
|
||||
|
||||
18
vendor/spomky-labs/otphp/RELEASES.md
vendored
Normal file
18
vendor/spomky-labs/otphp/RELEASES.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Versioning and Release
|
||||
|
||||
This document describes the versioning and release process of OTPHP.
|
||||
This document is a living document, contents will be updated according to each release.
|
||||
|
||||
## Releases
|
||||
|
||||
OTPHP releases will be versioned using dotted triples, similar to [Semantic Version](http://semver.org/).
|
||||
For this specific document, we will refer to the respective components of this triple as `<major>.<minor>.<patch>`.
|
||||
The version number may have additional information, such as "-rc1,-rc2,-rc3" to mark release candidate builds for earlier access.
|
||||
Such releases will be considered as "pre-releases".
|
||||
|
||||
## Minor Release Support Matrix
|
||||
|
||||
| Version | Supported |
|
||||
|----------|--------------------|
|
||||
| 11.4.x | :white_check_mark: |
|
||||
| < 11.4.x | :x: |
|
||||
145
vendor/spomky-labs/otphp/SECURITY.md
vendored
145
vendor/spomky-labs/otphp/SECURITY.md
vendored
@@ -1,87 +1,74 @@
|
||||
# Security Policy
|
||||
# Security Release Process
|
||||
|
||||
OTPHP is devoted to providing the best experience for all developers who want to implement OTP authentication in their applications.
|
||||
Spomky-Labs has adopted this security disclosure and response policy to ensure we responsibly handle critical issues.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| ------- |----------------------------------------|
|
||||
| 11.0.x | :white_check_mark: |
|
||||
| 10.0.x | :white_check_mark: (security fix only) |
|
||||
| < 10.0 | :x: |
|
||||
The OTPHP project maintains release branches for the three most recent minor releases.
|
||||
Applicable fixes, including security fixes, may be backported to those three release branches, depending on severity and feasibility. Please refer to [RELEASES.md](RELEASES.md) for details.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
## Reporting a Vulnerability - Private Disclosure Process
|
||||
|
||||
Please email `security@spomky-labs.com`.
|
||||
If deemed necessary, you can encrypt your message using one of the following GPG key
|
||||
Security is of the highest importance and all security vulnerabilities or suspected security vulnerabilities should be reported to OTPHP privately, to minimize attacks against current users of OTPHP before they are fixed.
|
||||
Vulnerabilities will be investigated and patched on the next patch (or minor) release as soon as possible.
|
||||
This information could be kept entirely internal to the project.
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
xjMEXTsJVxYJKwYBBAHaRw8BAQdAZCS93eHRx97V+LQbAWuAaeKIdUZ9YIkn
|
||||
QH5pQ7dDU0TNMWNvbnRhY3RAc3BvbWt5LWxhYnMuY29tIDxjb250YWN0QHNw
|
||||
b21reS1sYWJzLmNvbT7CdwQQFgoAHwUCXTsJVwYLCQcIAwIEFQgKAgMWAgEC
|
||||
GQECGwMCHgEACgkQG6hbCDSDj+1/tgEAoy11uHvDV7kkG/iN2/0ylV72hU8y
|
||||
c/xoqGd7qFaKD6ABANcthlg63OrQVTf0dUPOT9Y2BJpOOA88JJWgILtuUPIO
|
||||
zjgEXTsJVxIKKwYBBAGXVQEFAQEHQKiX7nldkmICePhzwReZnBPmjpsmNt7V
|
||||
Y8xHdICKsr8cAwEIB8JhBBgWCAAJBQJdOwlXAhsMAAoJEBuoWwg0g4/t0KgA
|
||||
/31ucb/bL/MGpWFrpSjTs6uQhZWlBmcFoeMhwCYepIpZAQDd65UBqFDKXJWv
|
||||
Xy3zoMQQzD9Z6fUATnFrWkzjHwhvDQ==
|
||||
=j4dw
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
If you know of a publicly disclosed security vulnerability for OTPHP, please **IMMEDIATELY** contact security@spomky-labs.com to inform the OTPHP Security Team.
|
||||
|
||||
**IMPORTANT: Do not file public issues on GitHub for security vulnerabilities**
|
||||
|
||||
```
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
xsFNBGILZFoBEADo9pzAMRVxL5typ22Ywifdyi3CMHgg7zptfb8otrQci8IX
|
||||
m7B8/NTA0I9EkenzSW/Mf4k2iPNCwXc+qVEHPvPNvr3WazcdiDQJjXqMtkxG
|
||||
l2dvdQHdBxN46v+mvWDVGf9anYQxIAmZrj7CDLOfD/cG/8STL4hSbFjRBOKs
|
||||
xAP8wgRA/amcrf9WcCDxURGIq8mDPcECR8fca+iukTmMe2NDEc56pJi0KVoF
|
||||
pFhOMMfjgP/XvtGjjSNZNGRgHSLTQs8UiK+5BjPh+iWFIPV5+ZPLpbSOcoma
|
||||
GyeX5i1DmAh7cWx/FphvFzOun6to3ERuy82+zW54iA9zS8+kIfV4Wjr2qE7l
|
||||
Ctc9l8RIv/6dMXoW2Y42CTuywlAMnlP7XaaUgE++CXTIuO7+6Gp0E5NlmqB5
|
||||
lb+CZLV/LS27gUcajs23ve5B3UId2bGUflvTtY/J0VPzrJMoEErVnkCsnD7W
|
||||
Oiwe8GiSNMJmTGu/A45xf5nuYNcuU7blA5XXwPoHZuALj1zv6eCWVxWz02l9
|
||||
Fc/T+gNkOEErlXOcldyXxQ5Qb99TU5NgdqzbibyR9QAqdfwtgg19oFbiSP7t
|
||||
8b5P2qAIW2GaOCkX007cBCzTXNrcQNruTwUD59LZQLhdGz5WJo/gefC/3ZvR
|
||||
vKoJKCRlk7s43aUjeZzE+Engpr5e1wl63WjAzQARAQABzTNzZWN1cml0eUBz
|
||||
cG9ta3ktbGFicy5jb20gPHNlY3VyaXR5QHNwb21reS1sYWJzLmNvbT7CwY0E
|
||||
EAEIACAFAmILZFoGCwkHCAMCBBUICgIEFgIBAAIZAQIbAwIeAQAhCRBy14gx
|
||||
FHv4aBYhBKgF8zJv89FYVv0RFHLXiDEUe/hoA+YP/ijaePtilKURzNVrPWfc
|
||||
gDw/ZNCR+dVAgwGo9VcbOvkyZmyqD6yBjuDWvG96KQs0LRrqWKonAvnewNtp
|
||||
wQruuvrlcCuNE6TTfvx0wh2+lwKD7MH5dKutHUCowVNAsZ5uZxHVF9RGLBh+
|
||||
JRofklupcGqUx+Jtx4uq2gAGOqV4/QdvneMjkLwqVu8FGIM59LfdNfp/iA3p
|
||||
wX2DvfxBO58Gu6hilmf7R+b9nX0U7xYJM6QJb7H89cV3/AoTh2kf1wtFY+Py
|
||||
Di6VZTMUBYOoz2iSnvCE8KlBWDu98/A2EJ7kDGQdmnuIgsURsyap3yKioaUr
|
||||
LGTaG0OiC/gkXkKisH6eff6Gw06qelBarf5N/GgoeAN/amE8twy3a+Hx1pyw
|
||||
ZzkjPsL7uWg3Koy5mPuCtWfPtIBcJaTLS5d8ESlJ8/CfaVaDludzYQZo70Xn
|
||||
m4KzjPnptm3djpZNwoFEUxrHVREOEe69/MnEL2PNcEMQkapg16PnH4phajnC
|
||||
7bYOPDteMJlHjNmQzz9d25ZwzVBHDDT50mHDijR2D/OgKx3NQr88fiFAWhKG
|
||||
lEu1ZuOkKIKV5VIFbocTWSoV7bkzIfrll49xWou+4VOxgRuqjquFC4RV8fea
|
||||
lLbHOcJlOR00aFDmoOWQ3/QNvajaWJFzDdocGbgbnEBMDFRoUkuhqOBcnzA+
|
||||
apW/zsFNBGILZFoBEADSwiM49wObRpxOyas91M6WvJ4Gt3iXqj+L8dmcw0FW
|
||||
UdDpwOxy8tuZx+OfXEBBH3eJHOobC66vN+E9WYobVkJ5zfbGxfQruTuvUZNl
|
||||
X9Lo0UwoP+AP21AKUUvsf48iZGWzmlkxgPnhAQS4ECkkWCKPf7nFTk+V+jIN
|
||||
nf6ZDZLXaRUnG0nLvzs0raG1eTVrGvPSCC8u3R2zIh9SvoeEgTnT/Re0mhCu
|
||||
ah3fwG+4vXc6VIjR1ZtpM9+Y8sl+PFZ/Oiisc+46oU5qXVVLtHfLdxYZ4vl2
|
||||
IflHDKKmrfbfGY1hJl/foBLglT3Cd8GTu3FjiAJX9PpkiWbsflc0OUBQf9aC
|
||||
73W5FLS4P4clm4nNzVGkNucWHvk+urM6nEUf02bhsfF0TPeos3QcJorfKNUS
|
||||
TvuGYccENuK5cVOzEcU+VhN08GT0pr0CpqJnsw+zV8vD4k3aPmMFmSVog+bY
|
||||
NhfB7AgwbOjd6MhQJcP7YjYTHaa6YsnKMSg4RhkDjvMa3421hfaWsVvlIb0f
|
||||
AZJ8BnXgfE0uI8CKA9dc6I2Posl33zC8HI2sS1MEJ90Am68P+uJt61LdJeD5
|
||||
VXSrCkzBhUBds0hbGR6+DF20UD496m7Lw3VBoWOl2bMeLdERDarFMDYsPH47
|
||||
rie9wlrnPNR57HUqK4bpkFwqTStRkRFUhFv7LLWZ1QARAQABwsF2BBgBCAAJ
|
||||
BQJiC2RaAhsMACEJEHLXiDEUe/hoFiEEqAXzMm/z0VhW/REUcteIMRR7+GhI
|
||||
lQ/9GbSwIdGue6Gw0msYAEoER9HhpYB//9/GG7/c4ZW60nLSSYuhNWIo0Akl
|
||||
10CzeApezf/O9/1EExqZ9ygj4wtUphcQOdRJVhXPt+gskw7/NHoXUJ+Z1rbb
|
||||
EWbKle9YufZ4PAKYhlxdqTlWyQvPVxrRvbuhYeQG4S412VzKjH0/x1Fh2CfV
|
||||
hFuyOaRjg89T6rihXL1rCSJ/PDQeQtvtXeJ30yFj+aapCj+VqUl+2D+N0bzS
|
||||
LL18kEPQnJw4BOHOXrw349dAKmHN/QkRH8DINlXLyaOlABglnSViDQL3Q1t3
|
||||
sBuIeClsl3brQNJRp/RKOdTBMNAX+BhAjqodbwwT+UkJl9xJKw0Cla4wtbs2
|
||||
T0yoK/Z1iFfvPdufkK4q6ocAHJUp3+XckFIZxsHQvhQPbm9XoOt1RTO29MOw
|
||||
EYo8UjFQCnXJVsj1/6XMgIUe5tPYvS/ZZZNJFF4j+OE8xRKLKqg/DFcpEipC
|
||||
LCmzzr/hhWx0XP4CIK2tYsAMk3ieCZuk1Wa+NGLL4WfALWsNHq3wg5Wzv+yJ
|
||||
dp14fv711BVYlriI+VKggGFgBdz0dWkgrBk4+thLatJFcjFYr8BLkbtPraa3
|
||||
sFI/cGxvOXSIy4GEALdfnozyU3RJtMNtVi3IzGeIFAOb457y/IrMqpWLp1FX
|
||||
BUqlX5YJHneD9Q8Sfz/HKDQDCqg=
|
||||
=o+4z
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
```
|
||||
To report a vulnerability or a security-related issue, please email the private address security@spomky-labs.com with the details of the vulnerability.
|
||||
The email will be fielded by the OTPHP Security Team, which is made up of the OTPHP maintainers who have committer and release permissions.
|
||||
Do not report non-security-impacting bugs through this channel. Use [GitHub issues](https://github.com/Spomky-Labs/otphp/issues/new/choose) instead.
|
||||
|
||||
Emails can be encrypted if you wish to share the vulnerability details securely.
|
||||
The OTPHP Security Team's PGP key is available on the [PGP keyservers](https://keys.openpgp.org/search?q=security%40spomky-labs.com).
|
||||
|
||||
### Proposed Email Content
|
||||
|
||||
Provide a descriptive subject line and in the body of the email include the following information:
|
||||
|
||||
- Basic identity information, such as your name and your affiliation or company.
|
||||
- Detailed steps to reproduce the vulnerability (POC scripts, screenshots, and compressed packet captures are all helpful to us).
|
||||
- Description of the effects of the vulnerability on OTPHP and the related hardware and software configurations, so that the OTPHP Security Team can reproduce it.
|
||||
- How the vulnerability affects OTPHP usage and an estimation of the attack surface, if there is one.
|
||||
- List other projects or dependencies that were used in conjunction with OTPHP to produce the vulnerability.
|
||||
|
||||
## When to report a vulnerability
|
||||
|
||||
- When you think OTPHP has a potential security vulnerability.
|
||||
- When you suspect a potential vulnerability, but you are unsure that it impacts OTPHP.
|
||||
- When you know of or suspect a potential vulnerability on another project that is used by OTPHP.
|
||||
|
||||
## Patch, Release, and Disclosure
|
||||
|
||||
The OTPHP Security Team will respond to vulnerability reports as follows:
|
||||
|
||||
1. The Security Team will investigate the vulnerability and determine its effects and criticality.
|
||||
2. If the issue is not deemed to be a vulnerability, the Security Team will follow up with a detailed reason for rejection.
|
||||
3. The Security Team will initiate a conversation with the reporter as soon as possible.
|
||||
4. If a vulnerability is acknowledged and the timeline for a fix is determined, the Security Team will work on a plan to communicate with the appropriate community, including identifying mitigating steps that affected users can take to protect themselves until the fix is rolled out.
|
||||
5. The Security Team will work on fixing the vulnerability and perform internal testing before preparing to roll out the fix.
|
||||
6. A public disclosure date is negotiated by the OTPHP Security Team and the bug submitter. We prefer to fully disclose the bug as soon as possible once a user mitigation or patch is available. It is reasonable to delay disclosure when the bug or the fix is not yet fully understood, the solution is not well-tested, or for distributor coordination. The timeframe for disclosure is from immediate (especially if it's already publicly known) to a few weeks. For a critical vulnerability with a straightforward mitigation, we expect report date to public disclosure date to be on the order of 14 business days. The OTPHP Security Team holds the final say when setting a public disclosure date.
|
||||
7. Once the fix is confirmed, the Security Team will patch the vulnerability in the next patch or minor release, and backport a patch release into all earlier supported releases. Upon release of the patched version of OTPHP, we will follow the **Public Disclosure Process**.
|
||||
|
||||
### Public Disclosure Process
|
||||
|
||||
The Security Team publishes a public [advisory](https://github.com/Spomky-Labs/otphp/security/advisories) to the OTPHP community via GitHub. In most cases, additional communication via Twitter, blog and other channels will assist in educating OTPHP users and rolling out the patched release to affected users.
|
||||
|
||||
The Security Team will also publish any mitigating steps users can take until the fix can be applied to their OTPHP instances. OTPHP distributors will handle creating and publishing their own security advisories.
|
||||
|
||||
## Mailing lists
|
||||
|
||||
- Use security@spomky-labs.com to report security concerns to the OTPHP Security Team, who uses the list to privately discuss security issues and fixes prior to disclosure.
|
||||
|
||||
## Early Disclosure to OTPHP Distributors List
|
||||
|
||||
This private list is intended to be used primarily to provide actionable information to multiple distributor projects at once. This list is not intended to inform individuals about security issues.
|
||||
|
||||
## Confidentiality, integrity and availability
|
||||
|
||||
We consider vulnerabilities leading to the compromise of data confidentiality, elevation of privilege, or integrity to be our highest priority concerns.
|
||||
Availability, in particular in areas relating to DoS and resource exhaustion, is also a serious security concern.
|
||||
The OTPHP Security Team takes all vulnerabilities, potential vulnerabilities, and suspected vulnerabilities seriously and will investigate them in an urgent and expeditious manner.
|
||||
|
||||
14
vendor/spomky-labs/otphp/composer.json
vendored
14
vendor/spomky-labs/otphp/composer.json
vendored
@@ -17,24 +17,12 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.1",
|
||||
"ext-mbstring": "*",
|
||||
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
|
||||
"psr/clock": "^1.0",
|
||||
"symfony/deprecation-contracts": "^3.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"ekino/phpstan-banned-code": "^1.0",
|
||||
"infection/infection": "^0.26|^0.27|^0.28|^0.29",
|
||||
"php-parallel-lint/php-parallel-lint": "^1.3",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-deprecation-rules": "^1.0",
|
||||
"phpstan/phpstan-phpunit": "^1.0",
|
||||
"phpstan/phpstan-strict-rules": "^1.0",
|
||||
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
|
||||
"qossmic/deptrac-shim": "^1.0",
|
||||
"rector/rector": "^1.0",
|
||||
"symfony/phpunit-bridge": "^6.1|^7.0",
|
||||
"symplify/easy-coding-standard": "^12.0"
|
||||
"symfony/error-handler": "^6.4|^7.0|^8.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "OTPHP\\": "src/" }
|
||||
|
||||
25
vendor/spomky-labs/otphp/src/Exception/InvalidLabelException.php
vendored
Normal file
25
vendor/spomky-labs/otphp/src/Exception/InvalidLabelException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Exception thrown when a label or issuer format is invalid.
|
||||
* This includes violations of the Google Authenticator label specification.
|
||||
*/
|
||||
final class InvalidLabelException extends InvalidArgumentException implements OTPExceptionInterface
|
||||
{
|
||||
public function __construct(
|
||||
string $message,
|
||||
public readonly string $labelName = '',
|
||||
public readonly mixed $labelValue = null,
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
25
vendor/spomky-labs/otphp/src/Exception/InvalidParameterException.php
vendored
Normal file
25
vendor/spomky-labs/otphp/src/Exception/InvalidParameterException.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Exception thrown when an OTP parameter has an invalid value.
|
||||
* This includes: secret, digits, algorithm, period, epoch, counter, secret size.
|
||||
*/
|
||||
final class InvalidParameterException extends InvalidArgumentException implements OTPExceptionInterface
|
||||
{
|
||||
public function __construct(
|
||||
string $message,
|
||||
public readonly string $parameterName = '',
|
||||
public readonly mixed $parameterValue = null,
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
15
vendor/spomky-labs/otphp/src/Exception/InvalidProvisioningUriException.php
vendored
Normal file
15
vendor/spomky-labs/otphp/src/Exception/InvalidProvisioningUriException.php
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a provisioning URI cannot be parsed or is invalid.
|
||||
* This includes: invalid format, wrong scheme, missing required parameters, unsupported OTP type.
|
||||
*/
|
||||
final class InvalidProvisioningUriException extends InvalidArgumentException implements OTPExceptionInterface
|
||||
{
|
||||
}
|
||||
16
vendor/spomky-labs/otphp/src/Exception/OTPExceptionInterface.php
vendored
Normal file
16
vendor/spomky-labs/otphp/src/Exception/OTPExceptionInterface.php
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Marker interface for all OTPHP exceptions.
|
||||
* This allows catching all OTPHP-specific exceptions while maintaining
|
||||
* backward compatibility with PHP's built-in exception types.
|
||||
*/
|
||||
interface OTPExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
23
vendor/spomky-labs/otphp/src/Exception/ParameterNotFoundException.php
vendored
Normal file
23
vendor/spomky-labs/otphp/src/Exception/ParameterNotFoundException.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Exception thrown when attempting to access a parameter that doesn't exist.
|
||||
*/
|
||||
final class ParameterNotFoundException extends InvalidArgumentException implements OTPExceptionInterface
|
||||
{
|
||||
public function __construct(
|
||||
string $message,
|
||||
public readonly string $parameterName = '',
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
14
vendor/spomky-labs/otphp/src/Exception/SecretDecodingException.php
vendored
Normal file
14
vendor/spomky-labs/otphp/src/Exception/SecretDecodingException.php
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a secret cannot be decoded from Base32.
|
||||
*/
|
||||
final class SecretDecodingException extends RuntimeException implements OTPExceptionInterface
|
||||
{
|
||||
}
|
||||
42
vendor/spomky-labs/otphp/src/Factory.php
vendored
42
vendor/spomky-labs/otphp/src/Factory.php
vendored
@@ -4,15 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OTPHP\Exception\InvalidProvisioningUriException;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use Throwable;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* This class is used to load OTP object from a provisioning Uri.
|
||||
*
|
||||
* @readonly
|
||||
*
|
||||
* @see \OTPHP\Test\FactoryTest
|
||||
*/
|
||||
final class Factory implements FactoryInterface
|
||||
@@ -21,9 +23,13 @@ final class Factory implements FactoryInterface
|
||||
{
|
||||
try {
|
||||
$parsed_url = Url::fromString($uri);
|
||||
$parsed_url->getScheme() === 'otpauth' || throw new InvalidArgumentException('Invalid scheme.');
|
||||
$parsed_url->getScheme() === 'otpauth' || throw new InvalidProvisioningUriException('Invalid scheme.');
|
||||
} catch (Throwable $throwable) {
|
||||
throw new InvalidArgumentException('Not a valid OTP provisioning URI', $throwable->getCode(), $throwable);
|
||||
throw new InvalidProvisioningUriException(
|
||||
'Not a valid OTP provisioning URI',
|
||||
$throwable->getCode(),
|
||||
$throwable
|
||||
);
|
||||
}
|
||||
if ($clock === null) {
|
||||
trigger_deprecation(
|
||||
@@ -51,7 +57,7 @@ final class Factory implements FactoryInterface
|
||||
private static function populateOTP(OTPInterface $otp, Url $data): void
|
||||
{
|
||||
self::populateParameters($otp, $data);
|
||||
$result = explode(':', rawurldecode(mb_substr($data->getPath(), 1)));
|
||||
$result = explode(':', rawurldecode(substr($data->getPath(), 1)));
|
||||
|
||||
if (count($result) < 2) {
|
||||
$otp->setIssuerIncludedAsParameter(false);
|
||||
@@ -59,16 +65,20 @@ final class Factory implements FactoryInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if ($otp->getIssuer() !== null) {
|
||||
$result[0] === $otp->getIssuer() || throw new InvalidArgumentException(
|
||||
'Invalid OTP: invalid issuer in parameter'
|
||||
);
|
||||
$issuerFromLabel = $result[0];
|
||||
$issuerFromParameter = $otp->getIssuer();
|
||||
|
||||
if ($issuerFromParameter !== null) {
|
||||
// Issuer parameter takes precedence over issuer in label
|
||||
// According to Google Authenticator spec: "they should be equal" but not required to be
|
||||
$otp->setIssuerIncludedAsParameter(true);
|
||||
} else {
|
||||
// No issuer parameter, use the issuer from label
|
||||
$issuerFromLabel !== '' || throw new InvalidProvisioningUriException(
|
||||
'Issuer from label must not be empty.'
|
||||
);
|
||||
$otp->setIssuer($issuerFromLabel);
|
||||
}
|
||||
|
||||
assert($result[0] !== '');
|
||||
|
||||
$otp->setIssuer($result[0]);
|
||||
}
|
||||
|
||||
private static function createOTP(Url $parsed_url, ClockInterface $clock): OTPInterface
|
||||
@@ -85,7 +95,7 @@ final class Factory implements FactoryInterface
|
||||
|
||||
return $hotp;
|
||||
default:
|
||||
throw new InvalidArgumentException(sprintf('Unsupported "%s" OTP type', $parsed_url->getHost()));
|
||||
throw new InvalidProvisioningUriException(sprintf('Unsupported "%s" OTP type', $parsed_url->getHost()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +105,9 @@ final class Factory implements FactoryInterface
|
||||
*/
|
||||
private static function getLabel(string $data): string
|
||||
{
|
||||
$result = explode(':', rawurldecode(mb_substr($data, 1)));
|
||||
$result = explode(':', rawurldecode(substr($data, 1)));
|
||||
$label = count($result) === 2 ? $result[1] : $result[0];
|
||||
assert($label !== '');
|
||||
$label !== '' || throw new InvalidProvisioningUriException('Label must not be empty.');
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
interface FactoryInterface
|
||||
{
|
||||
/**
|
||||
@@ -12,5 +14,5 @@ interface FactoryInterface
|
||||
*
|
||||
* @param non-empty-string $uri
|
||||
*/
|
||||
public static function loadFromProvisioningUri(string $uri): OTPInterface;
|
||||
public static function loadFromProvisioningUri(string $uri, ?ClockInterface $clock = null): OTPInterface;
|
||||
}
|
||||
|
||||
44
vendor/spomky-labs/otphp/src/HOTP.php
vendored
44
vendor/spomky-labs/otphp/src/HOTP.php
vendored
@@ -4,10 +4,14 @@ declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OTPHP\Exception\InvalidParameterException;
|
||||
use function is_int;
|
||||
|
||||
/**
|
||||
* Note: This class is not marked as readonly because the verify() method
|
||||
* updates the counter state on successful verification, which is an intentional
|
||||
* side-effect to prevent OTP reuse.
|
||||
*
|
||||
* @see \OTPHP\Test\HOTPTest
|
||||
*/
|
||||
final class HOTP extends OTP implements HOTPInterface
|
||||
@@ -18,11 +22,12 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
null|string $secret = null,
|
||||
int $counter = self::DEFAULT_COUNTER,
|
||||
string $digest = self::DEFAULT_DIGEST,
|
||||
int $digits = self::DEFAULT_DIGITS
|
||||
int $digits = self::DEFAULT_DIGITS,
|
||||
?int $secretSize = null
|
||||
): self {
|
||||
$htop = $secret !== null
|
||||
? self::createFromSecret($secret)
|
||||
: self::generate()
|
||||
: self::generate($secretSize)
|
||||
;
|
||||
$htop->setCounter($counter);
|
||||
$htop->setDigest($digest);
|
||||
@@ -41,9 +46,12 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
return $htop;
|
||||
}
|
||||
|
||||
public static function generate(): self
|
||||
/**
|
||||
* @param positive-int|null $secretSize
|
||||
*/
|
||||
public static function generate(?int $secretSize = null): self
|
||||
{
|
||||
return self::createFromSecret(self::generateSecret());
|
||||
return self::createFromSecret(self::generateSecret($secretSize));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +60,11 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
public function getCounter(): int
|
||||
{
|
||||
$value = $this->getParameter('counter');
|
||||
(is_int($value) && $value >= 0) || throw new InvalidArgumentException('Invalid "counter" parameter.');
|
||||
(is_int($value) && $value >= 0) || throw new InvalidParameterException(
|
||||
'Invalid "counter" parameter.',
|
||||
'counter',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
@@ -71,7 +83,11 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
*/
|
||||
public function verify(string $otp, null|int $counter = null, null|int $window = null): bool
|
||||
{
|
||||
$counter >= 0 || throw new InvalidArgumentException('The counter must be at least 0.');
|
||||
$counter >= 0 || throw new InvalidParameterException(
|
||||
'The counter must be at least 0.',
|
||||
'counter',
|
||||
$counter
|
||||
);
|
||||
|
||||
if ($counter === null) {
|
||||
$counter = $this->getCounter();
|
||||
@@ -87,6 +103,14 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
$this->setParameter('counter', $counter);
|
||||
}
|
||||
|
||||
public function withCounter(int $counter): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('counter', $counter);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, callable>
|
||||
*/
|
||||
@@ -95,7 +119,11 @@ final class HOTP extends OTP implements HOTPInterface
|
||||
return [...parent::getParameterMap(), ...[
|
||||
'counter' => static function (mixed $value): int {
|
||||
$value = (int) $value;
|
||||
$value >= 0 || throw new InvalidArgumentException('Counter must be at least 0.');
|
||||
$value >= 0 || throw new InvalidParameterException(
|
||||
'Counter must be at least 0.',
|
||||
'counter',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
},
|
||||
|
||||
@@ -32,5 +32,10 @@ interface HOTPInterface extends OTPInterface
|
||||
int $digits = 6
|
||||
): self;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withCounter()} instead
|
||||
*/
|
||||
public function setCounter(int $counter): void;
|
||||
|
||||
public function withCounter(int $counter): self;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use DateTimeImmutable;
|
||||
use Psr\Clock\ClockInterface;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class InternalClock implements ClockInterface
|
||||
|
||||
372
vendor/spomky-labs/otphp/src/OTP.php
vendored
372
vendor/spomky-labs/otphp/src/OTP.php
vendored
@@ -5,21 +5,44 @@ declare(strict_types=1);
|
||||
namespace OTPHP;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use OTPHP\Exception\InvalidLabelException;
|
||||
use OTPHP\Exception\InvalidParameterException;
|
||||
use OTPHP\Exception\ParameterNotFoundException;
|
||||
use OTPHP\Exception\SecretDecodingException;
|
||||
use ParagonIE\ConstantTime\Base32;
|
||||
use RuntimeException;
|
||||
use function assert;
|
||||
use function array_key_exists;
|
||||
use function chr;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
use const STR_PAD_LEFT;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
*/
|
||||
abstract class OTP implements OTPInterface
|
||||
{
|
||||
use ParameterTrait;
|
||||
|
||||
private const DEFAULT_SECRET_SIZE = 64;
|
||||
|
||||
/**
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
private array $parameters = [];
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private null|string $issuer = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private null|string $label = null;
|
||||
|
||||
private bool $issuer_included_as_parameter = true;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $secret
|
||||
*/
|
||||
@@ -44,11 +67,201 @@ abstract class OTP implements OTPInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function getParameters(): array
|
||||
{
|
||||
$parameters = $this->parameters;
|
||||
|
||||
if ($this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true) {
|
||||
$parameters['issuer'] = $this->getIssuer();
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
public function getSecret(): string
|
||||
{
|
||||
$value = $this->getParameter('secret');
|
||||
(is_string($value) && $value !== '') || throw new InvalidParameterException(
|
||||
'Invalid "secret" parameter.',
|
||||
'secret',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getLabel(): null|string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $label): void
|
||||
{
|
||||
$this->setParameter('label', $label);
|
||||
}
|
||||
|
||||
public function withLabel(string $label): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('label', $label);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function getIssuer(): null|string
|
||||
{
|
||||
return $this->issuer;
|
||||
}
|
||||
|
||||
public function setIssuer(string $issuer): void
|
||||
{
|
||||
$this->setParameter('issuer', $issuer);
|
||||
}
|
||||
|
||||
public function withIssuer(string $issuer): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('issuer', $issuer);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function isIssuerIncludedAsParameter(): bool
|
||||
{
|
||||
return $this->issuer_included_as_parameter;
|
||||
}
|
||||
|
||||
public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void
|
||||
{
|
||||
$this->issuer_included_as_parameter = $issuer_included_as_parameter;
|
||||
}
|
||||
|
||||
public function withIssuerIncludedAsParameter(bool $issuer_included_as_parameter): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->issuer_included_as_parameter = $issuer_included_as_parameter;
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function getDigits(): int
|
||||
{
|
||||
$value = $this->getParameter('digits');
|
||||
(is_int($value) && $value > 0) || throw new InvalidParameterException(
|
||||
'Invalid "digits" parameter.',
|
||||
'digits',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getDigest(): string
|
||||
{
|
||||
$value = $this->getParameter('algorithm');
|
||||
(is_string($value) && $value !== '') || throw new InvalidParameterException(
|
||||
'Invalid "algorithm" parameter.',
|
||||
'algorithm',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function hasParameter(string $parameter): bool
|
||||
{
|
||||
return array_key_exists($parameter, $this->parameters);
|
||||
}
|
||||
|
||||
public function getParameter(string $parameter): mixed
|
||||
{
|
||||
if ($this->hasParameter($parameter)) {
|
||||
return $this->getParameters()[$parameter];
|
||||
}
|
||||
|
||||
throw new ParameterNotFoundException(sprintf('Parameter "%s" does not exist', $parameter), $parameter);
|
||||
}
|
||||
|
||||
public function setParameter(string $parameter, mixed $value): void
|
||||
{
|
||||
$map = $this->getParameterMap();
|
||||
|
||||
if (array_key_exists($parameter, $map) === true) {
|
||||
$callback = $map[$parameter];
|
||||
$value = $callback($value);
|
||||
}
|
||||
|
||||
if (property_exists($this, $parameter)) {
|
||||
$this->{$parameter} = $value;
|
||||
} else {
|
||||
$this->parameters[$parameter] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function withParameter(string $parameter, mixed $value): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter($parameter, $value);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function setSecret(string $secret): void
|
||||
{
|
||||
$this->setParameter('secret', $secret);
|
||||
}
|
||||
|
||||
public function withSecret(string $secret): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('secret', $secret);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function setDigits(int $digits): void
|
||||
{
|
||||
$this->setParameter('digits', $digits);
|
||||
}
|
||||
|
||||
public function withDigits(int $digits): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('digits', $digits);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function setDigest(string $digest): void
|
||||
{
|
||||
$this->setParameter('algorithm', $digest);
|
||||
}
|
||||
|
||||
public function withDigest(string $digest): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('algorithm', $digest);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param positive-int|null $secretSize
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
final protected static function generateSecret(): string
|
||||
final protected static function generateSecret(?int $secretSize = null): string
|
||||
{
|
||||
return Base32::encodeUpper(random_bytes(self::DEFAULT_SECRET_SIZE));
|
||||
$secretSize ??= self::DEFAULT_SECRET_SIZE;
|
||||
$secretSize > 0 || throw new InvalidParameterException(
|
||||
'Secret size must be at least 1.',
|
||||
'secretSize',
|
||||
$secretSize
|
||||
);
|
||||
|
||||
return Base32::encodeUpper(random_bytes($secretSize));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +275,7 @@ abstract class OTP implements OTPInterface
|
||||
{
|
||||
$hash = hash_hmac($this->getDigest(), $this->intToByteString($input), $this->getDecodedSecret(), true);
|
||||
$unpacked = unpack('C*', $hash);
|
||||
$unpacked !== false || throw new InvalidArgumentException('Invalid data.');
|
||||
$unpacked !== false || throw new InvalidParameterException('Invalid data.', 'hash', $hash);
|
||||
$hmac = array_values($unpacked);
|
||||
|
||||
$offset = ($hmac[count($hmac) - 1] & 0xF);
|
||||
@@ -98,19 +311,11 @@ abstract class OTP implements OTPInterface
|
||||
*/
|
||||
protected function generateURI(string $type, array $options): string
|
||||
{
|
||||
$label = $this->getLabel();
|
||||
is_string($label) || throw new InvalidArgumentException('The label is not set.');
|
||||
$this->hasColon($label) === false || throw new InvalidArgumentException('Label must not contain a colon.');
|
||||
$options = [...$options, ...$this->getParameters()];
|
||||
$this->filterOptions($options);
|
||||
$params = str_replace(['+', '%7E'], ['%20', '~'], http_build_query($options, '', '&'));
|
||||
|
||||
return sprintf(
|
||||
'otpauth://%s/%s?%s',
|
||||
$type,
|
||||
rawurlencode(($this->getIssuer() !== null ? $this->getIssuer() . ':' : '') . $label),
|
||||
$params
|
||||
);
|
||||
return sprintf('otpauth://%s/%s?%s', $type, rawurlencode($this->buildProvisioningUriLabel()), $params);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,6 +327,47 @@ abstract class OTP implements OTPInterface
|
||||
return hash_equals($safe, $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, callable>
|
||||
*/
|
||||
protected function getParameterMap(): array
|
||||
{
|
||||
return [
|
||||
'label' => function (string $value): string {
|
||||
$value !== '' || throw new InvalidLabelException('Label must not be empty.', 'label', $value);
|
||||
$this->validateLabel($value);
|
||||
|
||||
return $value;
|
||||
},
|
||||
'secret' => static fn (string $value): string => strtoupper(trim($value, '=')),
|
||||
'algorithm' => static function (string $value): string {
|
||||
$value = strtolower($value);
|
||||
in_array($value, hash_algos(), true) || throw new InvalidParameterException(
|
||||
sprintf('The "%s" digest is not supported.', $value),
|
||||
'algorithm',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
},
|
||||
'digits' => static function ($value): int {
|
||||
$value > 0 || throw new InvalidParameterException('Digits must be at least 1.', 'digits', $value);
|
||||
|
||||
return (int) $value;
|
||||
},
|
||||
'issuer' => function (string $value): string {
|
||||
$value !== '' || throw new InvalidLabelException('Issuer must not be empty.', 'issuer', $value);
|
||||
$this->hasColon($value) === false || throw new InvalidLabelException(
|
||||
'Issuer must not contain a colon.',
|
||||
'issuer',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
@@ -130,9 +376,9 @@ abstract class OTP implements OTPInterface
|
||||
try {
|
||||
$decoded = Base32::decodeUpper($this->getSecret());
|
||||
} catch (Exception) {
|
||||
throw new RuntimeException('Unable to decode the secret. Is it correctly base32 encoded?');
|
||||
throw new SecretDecodingException('Unable to decode the secret. Is it correctly base32 encoded?');
|
||||
}
|
||||
assert($decoded !== '');
|
||||
$decoded !== '' || throw new SecretDecodingException('The decoded secret must not be empty.');
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
@@ -147,4 +393,92 @@ abstract class OTP implements OTPInterface
|
||||
|
||||
return str_pad(implode('', array_reverse($result)), 8, "\000", STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
private function buildProvisioningUriLabel(): string
|
||||
{
|
||||
$issuer = $this->getIssuer();
|
||||
$label = $this->getLabel();
|
||||
|
||||
return match (true) {
|
||||
$issuer === null && $label === null => throw new InvalidLabelException(
|
||||
'The label is not set. Either label or issuer must be set.',
|
||||
'label'
|
||||
),
|
||||
$label !== null && $this->hasColon($label) => throw new InvalidLabelException(
|
||||
'Label must not contain a colon.',
|
||||
'label',
|
||||
$label
|
||||
),
|
||||
$issuer !== null && $label !== null => $issuer . ':' . $label,
|
||||
$issuer !== null => $issuer,
|
||||
default => $label,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a label according to Google Authenticator spec:
|
||||
* label = accountname / issuer (":" / "%3A") *"%20" accountname
|
||||
* Neither issuer nor account name may themselves contain a colon.
|
||||
*
|
||||
* Valid examples:
|
||||
* - alice@gmail.com
|
||||
* - Provider1:Alice%20Smith
|
||||
* - Big%20Corporation%3A%20alice%40bigco.com
|
||||
*
|
||||
* @param non-empty-string $value
|
||||
*/
|
||||
private function validateLabel(string $value): void
|
||||
{
|
||||
// Check for colon separators (literal or URL-encoded)
|
||||
$hasLiteralColon = str_contains($value, ':');
|
||||
$hasEncodedColon = str_contains($value, '%3A') || str_contains($value, '%3a');
|
||||
|
||||
if (! $hasLiteralColon && ! $hasEncodedColon) {
|
||||
// Simple label (account name only) - no colons allowed anywhere
|
||||
return;
|
||||
}
|
||||
|
||||
// Label contains a separator - validate issuer:account format
|
||||
// Split by literal or encoded colon
|
||||
$parts = match (true) {
|
||||
$hasLiteralColon => explode(':', $value, 2),
|
||||
default => preg_split('/%3[Aa]/', $value, 2),
|
||||
};
|
||||
|
||||
if ($parts === false || count($parts) !== 2) {
|
||||
throw new InvalidLabelException('Label must not contain a colon.', 'label', $value);
|
||||
}
|
||||
|
||||
[$issuerPart, $accountPart] = $parts;
|
||||
|
||||
// Remove leading %20 (spaces) from account part per spec: *"%20" accountname
|
||||
$accountPart = ltrim($accountPart, '%20');
|
||||
|
||||
// Validate that neither part contains additional colons
|
||||
if ($this->hasColon($issuerPart) || $this->hasColon($accountPart)) {
|
||||
throw new InvalidLabelException(
|
||||
'Neither issuer nor account name in label may contain a colon.',
|
||||
'label',
|
||||
$value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $value
|
||||
*/
|
||||
private function hasColon(string $value): bool
|
||||
{
|
||||
$colons = [':', '%3A', '%3a'];
|
||||
foreach ($colons as $colon) {
|
||||
if (str_contains($value, $colon)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
47
vendor/spomky-labs/otphp/src/OTPInterface.php
vendored
47
vendor/spomky-labs/otphp/src/OTPInterface.php
vendored
@@ -24,15 +24,34 @@ interface OTPInterface
|
||||
|
||||
/**
|
||||
* @param non-empty-string $secret
|
||||
*
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withSecret()} instead
|
||||
*/
|
||||
public function setSecret(string $secret): void;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $secret
|
||||
*/
|
||||
public function withSecret(string $secret): self;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withDigits()} instead
|
||||
*/
|
||||
public function setDigits(int $digits): void;
|
||||
|
||||
public function withDigits(int $digits): self;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $digest
|
||||
*
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withDigest()} instead
|
||||
*/
|
||||
public function setDigest(string $digest): void;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $digest
|
||||
*/
|
||||
public function setDigest(string $digest): void;
|
||||
public function withDigest(string $digest): self;
|
||||
|
||||
/**
|
||||
* Generate the OTP at the specified input.
|
||||
@@ -60,9 +79,16 @@ interface OTPInterface
|
||||
|
||||
/**
|
||||
* @param non-empty-string $label The label of the OTP
|
||||
*
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withLabel()} instead
|
||||
*/
|
||||
public function setLabel(string $label): void;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $label The label of the OTP
|
||||
*/
|
||||
public function withLabel(string $label): self;
|
||||
|
||||
/**
|
||||
* @return non-empty-string|null The label of the OTP
|
||||
*/
|
||||
@@ -75,16 +101,28 @@ interface OTPInterface
|
||||
|
||||
/**
|
||||
* @param non-empty-string $issuer
|
||||
*
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withIssuer()} instead
|
||||
*/
|
||||
public function setIssuer(string $issuer): void;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $issuer
|
||||
*/
|
||||
public function withIssuer(string $issuer): self;
|
||||
|
||||
/**
|
||||
* @return bool If true, the issuer will be added as a parameter in the provisioning URI
|
||||
*/
|
||||
public function isIssuerIncludedAsParameter(): bool;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withIssuerIncludedAsParameter()} instead
|
||||
*/
|
||||
public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void;
|
||||
|
||||
public function withIssuerIncludedAsParameter(bool $issuer_included_as_parameter): self;
|
||||
|
||||
/**
|
||||
* @return positive-int Number of digits in the OTP
|
||||
*/
|
||||
@@ -112,9 +150,16 @@ interface OTPInterface
|
||||
|
||||
/**
|
||||
* @param non-empty-string $parameter
|
||||
*
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withParameter()} instead
|
||||
*/
|
||||
public function setParameter(string $parameter, mixed $value): void;
|
||||
|
||||
/**
|
||||
* @param non-empty-string $parameter
|
||||
*/
|
||||
public function withParameter(string $parameter, mixed $value): self;
|
||||
|
||||
/**
|
||||
* Get the provisioning URI.
|
||||
*
|
||||
|
||||
200
vendor/spomky-labs/otphp/src/ParameterTrait.php
vendored
200
vendor/spomky-labs/otphp/src/ParameterTrait.php
vendored
@@ -1,200 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use function array_key_exists;
|
||||
use function assert;
|
||||
use function in_array;
|
||||
use function is_int;
|
||||
use function is_string;
|
||||
|
||||
trait ParameterTrait
|
||||
{
|
||||
/**
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
private array $parameters = [];
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private null|string $issuer = null;
|
||||
|
||||
/**
|
||||
* @var non-empty-string|null
|
||||
*/
|
||||
private null|string $label = null;
|
||||
|
||||
private bool $issuer_included_as_parameter = true;
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function getParameters(): array
|
||||
{
|
||||
$parameters = $this->parameters;
|
||||
|
||||
if ($this->getIssuer() !== null && $this->isIssuerIncludedAsParameter() === true) {
|
||||
$parameters['issuer'] = $this->getIssuer();
|
||||
}
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
public function getSecret(): string
|
||||
{
|
||||
$value = $this->getParameter('secret');
|
||||
(is_string($value) && $value !== '') || throw new InvalidArgumentException('Invalid "secret" parameter.');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getLabel(): null|string
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setLabel(string $label): void
|
||||
{
|
||||
$this->setParameter('label', $label);
|
||||
}
|
||||
|
||||
public function getIssuer(): null|string
|
||||
{
|
||||
return $this->issuer;
|
||||
}
|
||||
|
||||
public function setIssuer(string $issuer): void
|
||||
{
|
||||
$this->setParameter('issuer', $issuer);
|
||||
}
|
||||
|
||||
public function isIssuerIncludedAsParameter(): bool
|
||||
{
|
||||
return $this->issuer_included_as_parameter;
|
||||
}
|
||||
|
||||
public function setIssuerIncludedAsParameter(bool $issuer_included_as_parameter): void
|
||||
{
|
||||
$this->issuer_included_as_parameter = $issuer_included_as_parameter;
|
||||
}
|
||||
|
||||
public function getDigits(): int
|
||||
{
|
||||
$value = $this->getParameter('digits');
|
||||
(is_int($value) && $value > 0) || throw new InvalidArgumentException('Invalid "digits" parameter.');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getDigest(): string
|
||||
{
|
||||
$value = $this->getParameter('algorithm');
|
||||
(is_string($value) && $value !== '') || throw new InvalidArgumentException('Invalid "algorithm" parameter.');
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function hasParameter(string $parameter): bool
|
||||
{
|
||||
return array_key_exists($parameter, $this->parameters);
|
||||
}
|
||||
|
||||
public function getParameter(string $parameter): mixed
|
||||
{
|
||||
if ($this->hasParameter($parameter)) {
|
||||
return $this->getParameters()[$parameter];
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException(sprintf('Parameter "%s" does not exist', $parameter));
|
||||
}
|
||||
|
||||
public function setParameter(string $parameter, mixed $value): void
|
||||
{
|
||||
$map = $this->getParameterMap();
|
||||
|
||||
if (array_key_exists($parameter, $map) === true) {
|
||||
$callback = $map[$parameter];
|
||||
$value = $callback($value);
|
||||
}
|
||||
|
||||
if (property_exists($this, $parameter)) {
|
||||
$this->{$parameter} = $value;
|
||||
} else {
|
||||
$this->parameters[$parameter] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function setSecret(string $secret): void
|
||||
{
|
||||
$this->setParameter('secret', $secret);
|
||||
}
|
||||
|
||||
public function setDigits(int $digits): void
|
||||
{
|
||||
$this->setParameter('digits', $digits);
|
||||
}
|
||||
|
||||
public function setDigest(string $digest): void
|
||||
{
|
||||
$this->setParameter('algorithm', $digest);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, callable>
|
||||
*/
|
||||
protected function getParameterMap(): array
|
||||
{
|
||||
return [
|
||||
'label' => function (string $value): string {
|
||||
assert($value !== '');
|
||||
$this->hasColon($value) === false || throw new InvalidArgumentException(
|
||||
'Label must not contain a colon.'
|
||||
);
|
||||
|
||||
return $value;
|
||||
},
|
||||
'secret' => static fn (string $value): string => mb_strtoupper(trim($value, '=')),
|
||||
'algorithm' => static function (string $value): string {
|
||||
$value = mb_strtolower($value);
|
||||
in_array($value, hash_algos(), true) || throw new InvalidArgumentException(sprintf(
|
||||
'The "%s" digest is not supported.',
|
||||
$value
|
||||
));
|
||||
|
||||
return $value;
|
||||
},
|
||||
'digits' => static function ($value): int {
|
||||
$value > 0 || throw new InvalidArgumentException('Digits must be at least 1.');
|
||||
|
||||
return (int) $value;
|
||||
},
|
||||
'issuer' => function (string $value): string {
|
||||
assert($value !== '');
|
||||
$this->hasColon($value) === false || throw new InvalidArgumentException(
|
||||
'Issuer must not contain a colon.'
|
||||
);
|
||||
|
||||
return $value;
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param non-empty-string $value
|
||||
*/
|
||||
private function hasColon(string $value): bool
|
||||
{
|
||||
$colons = [':', '%3A', '%3a'];
|
||||
foreach ($colons as $colon) {
|
||||
if (str_contains($value, $colon)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
85
vendor/spomky-labs/otphp/src/TOTP.php
vendored
85
vendor/spomky-labs/otphp/src/TOTP.php
vendored
@@ -4,12 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OTPHP\Exception\InvalidParameterException;
|
||||
use Psr\Clock\ClockInterface;
|
||||
use function assert;
|
||||
use function is_int;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
*
|
||||
* @see \OTPHP\Test\TOTPTest
|
||||
*/
|
||||
final class TOTP extends OTP implements TOTPInterface
|
||||
@@ -37,11 +38,12 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
string $digest = self::DEFAULT_DIGEST,
|
||||
int $digits = self::DEFAULT_DIGITS,
|
||||
int $epoch = self::DEFAULT_EPOCH,
|
||||
?ClockInterface $clock = null
|
||||
?ClockInterface $clock = null,
|
||||
?int $secretSize = null
|
||||
): self {
|
||||
$totp = $secret !== null
|
||||
? self::createFromSecret($secret, $clock)
|
||||
: self::generate($clock)
|
||||
: self::generate($clock, $secretSize)
|
||||
;
|
||||
$totp->setPeriod($period);
|
||||
$totp->setDigest($digest);
|
||||
@@ -62,15 +64,22 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
return $totp;
|
||||
}
|
||||
|
||||
public static function generate(?ClockInterface $clock = null): self
|
||||
/**
|
||||
* @param positive-int|null $secretSize
|
||||
*/
|
||||
public static function generate(?ClockInterface $clock = null, ?int $secretSize = null): self
|
||||
{
|
||||
return self::createFromSecret(self::generateSecret(), $clock);
|
||||
return self::createFromSecret(self::generateSecret($secretSize), $clock);
|
||||
}
|
||||
|
||||
public function getPeriod(): int
|
||||
{
|
||||
$value = $this->getParameter('period');
|
||||
(is_int($value) && $value > 0) || throw new InvalidArgumentException('Invalid "period" parameter.');
|
||||
(is_int($value) && $value > 0) || throw new InvalidParameterException(
|
||||
'Invalid "period" parameter.',
|
||||
'period',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
@@ -78,7 +87,11 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
public function getEpoch(): int
|
||||
{
|
||||
$value = $this->getParameter('epoch');
|
||||
(is_int($value) && $value >= 0) || throw new InvalidArgumentException('Invalid "epoch" parameter.');
|
||||
(is_int($value) && $value >= 0) || throw new InvalidParameterException(
|
||||
'Invalid "epoch" parameter.',
|
||||
'epoch',
|
||||
$value
|
||||
);
|
||||
|
||||
return $value;
|
||||
}
|
||||
@@ -87,7 +100,7 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
{
|
||||
$period = $this->getPeriod();
|
||||
|
||||
return $period - ($this->clock->now()->getTimestamp() % $this->getPeriod());
|
||||
return $period - (($this->clock->now()->getTimestamp() - $this->getEpoch()) % $period);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,7 +117,11 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
{
|
||||
$timestamp = $this->clock->now()
|
||||
->getTimestamp();
|
||||
assert($timestamp >= 0, 'The timestamp must return a positive integer.');
|
||||
$timestamp >= 0 || throw new InvalidParameterException(
|
||||
'The timestamp must return a positive integer.',
|
||||
'timestamp',
|
||||
$timestamp
|
||||
);
|
||||
|
||||
return $this->at($timestamp);
|
||||
}
|
||||
@@ -120,19 +137,27 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
{
|
||||
$timestamp ??= $this->clock->now()
|
||||
->getTimestamp();
|
||||
$timestamp >= 0 || throw new InvalidArgumentException('Timestamp must be at least 0.');
|
||||
$timestamp >= 0 || throw new InvalidParameterException(
|
||||
'Timestamp must be at least 0.',
|
||||
'timestamp',
|
||||
$timestamp
|
||||
);
|
||||
|
||||
if ($leeway === null) {
|
||||
return $this->compareOTP($this->at($timestamp), $otp);
|
||||
}
|
||||
|
||||
$leeway = abs($leeway);
|
||||
$leeway < $this->getPeriod() || throw new InvalidArgumentException(
|
||||
'The leeway must be lower than the TOTP period'
|
||||
$leeway < $this->getPeriod() || throw new InvalidParameterException(
|
||||
'The leeway must be lower than the TOTP period',
|
||||
'leeway',
|
||||
$leeway
|
||||
);
|
||||
$timestampMinusLeeway = $timestamp - $leeway;
|
||||
$timestampMinusLeeway >= 0 || throw new InvalidArgumentException(
|
||||
'The timestamp must be greater than or equal to the leeway.'
|
||||
$timestampMinusLeeway >= 0 || throw new InvalidParameterException(
|
||||
'The timestamp must be greater than or equal to the leeway.',
|
||||
'timestamp',
|
||||
$timestamp
|
||||
);
|
||||
|
||||
return $this->compareOTP($this->at($timestampMinusLeeway), $otp)
|
||||
@@ -159,11 +184,27 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
$this->setParameter('period', $period);
|
||||
}
|
||||
|
||||
public function withPeriod(int $period): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('period', $period);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
public function setEpoch(int $epoch): void
|
||||
{
|
||||
$this->setParameter('epoch', $epoch);
|
||||
}
|
||||
|
||||
public function withEpoch(int $epoch): self
|
||||
{
|
||||
$otp = clone $this;
|
||||
$otp->setParameter('epoch', $epoch);
|
||||
|
||||
return $otp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<non-empty-string, callable>
|
||||
*/
|
||||
@@ -172,13 +213,15 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
return [
|
||||
...parent::getParameterMap(),
|
||||
'period' => static function ($value): int {
|
||||
(int) $value > 0 || throw new InvalidArgumentException('Period must be at least 1.');
|
||||
(int) $value > 0 || throw new InvalidParameterException('Period must be at least 1.', 'period', $value);
|
||||
|
||||
return (int) $value;
|
||||
},
|
||||
'epoch' => static function ($value): int {
|
||||
(int) $value >= 0 || throw new InvalidArgumentException(
|
||||
'Epoch must be greater than or equal to 0.'
|
||||
(int) $value >= 0 || throw new InvalidParameterException(
|
||||
'Epoch must be greater than or equal to 0.',
|
||||
'epoch',
|
||||
$value
|
||||
);
|
||||
|
||||
return (int) $value;
|
||||
@@ -208,7 +251,11 @@ final class TOTP extends OTP implements TOTPInterface
|
||||
private function timecode(int $timestamp): int
|
||||
{
|
||||
$timecode = (int) floor(($timestamp - $this->getEpoch()) / $this->getPeriod());
|
||||
assert($timecode >= 0);
|
||||
$timecode >= 0 || throw new InvalidParameterException(
|
||||
'Timecode must be at least 0. The timestamp must be greater than or equal to the epoch.',
|
||||
'timecode',
|
||||
$timecode
|
||||
);
|
||||
|
||||
return $timecode;
|
||||
}
|
||||
|
||||
10
vendor/spomky-labs/otphp/src/TOTPInterface.php
vendored
10
vendor/spomky-labs/otphp/src/TOTPInterface.php
vendored
@@ -29,10 +29,20 @@ interface TOTPInterface extends OTPInterface
|
||||
int $digits = self::DEFAULT_DIGITS
|
||||
): self;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withPeriod()} instead
|
||||
*/
|
||||
public function setPeriod(int $period): void;
|
||||
|
||||
public function withPeriod(int $period): self;
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated since v11.4, use {@see self::withEpoch()} instead
|
||||
*/
|
||||
public function setEpoch(int $epoch): void;
|
||||
|
||||
public function withEpoch(int $epoch): self;
|
||||
|
||||
/**
|
||||
* Return the TOTP at the current time.
|
||||
*
|
||||
|
||||
18
vendor/spomky-labs/otphp/src/Url.php
vendored
18
vendor/spomky-labs/otphp/src/Url.php
vendored
@@ -4,11 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace OTPHP;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use OTPHP\Exception\InvalidProvisioningUriException;
|
||||
use function array_key_exists;
|
||||
use function is_string;
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Url
|
||||
@@ -75,9 +77,9 @@ final class Url
|
||||
public static function fromString(string $uri): self
|
||||
{
|
||||
$parsed_url = parse_url($uri);
|
||||
$parsed_url !== false || throw new InvalidArgumentException('Invalid URI.');
|
||||
$parsed_url !== false || throw new InvalidProvisioningUriException('Invalid URI.');
|
||||
foreach (['scheme', 'host', 'path', 'query'] as $key) {
|
||||
array_key_exists($key, $parsed_url) || throw new InvalidArgumentException(
|
||||
array_key_exists($key, $parsed_url) || throw new InvalidProvisioningUriException(
|
||||
'Not a valid OTP provisioning URI'
|
||||
);
|
||||
}
|
||||
@@ -85,13 +87,13 @@ final class Url
|
||||
$host = $parsed_url['host'] ?? null;
|
||||
$path = $parsed_url['path'] ?? null;
|
||||
$query = $parsed_url['query'] ?? null;
|
||||
$scheme === 'otpauth' || throw new InvalidArgumentException('Not a valid OTP provisioning URI');
|
||||
is_string($host) || throw new InvalidArgumentException('Invalid URI.');
|
||||
is_string($path) || throw new InvalidArgumentException('Invalid URI.');
|
||||
is_string($query) || throw new InvalidArgumentException('Invalid URI.');
|
||||
$scheme === 'otpauth' || throw new InvalidProvisioningUriException('Not a valid OTP provisioning URI');
|
||||
is_string($host) || throw new InvalidProvisioningUriException('Invalid URI.');
|
||||
is_string($path) || throw new InvalidProvisioningUriException('Invalid URI.');
|
||||
is_string($query) || throw new InvalidProvisioningUriException('Invalid URI.');
|
||||
$parsedQuery = [];
|
||||
parse_str($query, $parsedQuery);
|
||||
array_key_exists('secret', $parsedQuery) || throw new InvalidArgumentException(
|
||||
array_key_exists('secret', $parsedQuery) || throw new InvalidProvisioningUriException(
|
||||
'Not a valid OTP provisioning URI'
|
||||
);
|
||||
$secret = $parsedQuery['secret'];
|
||||
|
||||
Reference in New Issue
Block a user